这里只举几个线程池newFixedThreadPool实用的列子,想要更深入一些可以去《java线程池之newFixedThreadPool》进行初步了解。
一、被调用的方法
先来三个要被调用的测试方法
1.1 无参数,无返回值
/**
* 无参数,无返回值
*/
private void hello01() {
try {
Thread.sleep(5000);
LOG.info("线程[" + Thread.currentThread().getName() + "]执行方法hello01()完毕,无参数无返回数据,异步执行");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
1.2 无参数,有返回值
/**
* 无参数,有返回值
*/
private String hello02() {
try {
Thread.sleep(3000);
LOG.info("线程[" + Thread.currentThread().getName() + "]执行方法hello02()完毕,无参数有返回数据,需等待线程执行完毕");
} catch (InterruptedException e) {
e.printStackTrace();
}
// 返回随意的一串字符串
return "我返回的是随机字符串:" + UUID.randomUUID().toString();
}
1.3 有参数,无返回值
/**
* 有参数,无返回值
*/
private void hello03(String name) {
try {
Thread.sleep(5000);
LOG.info(name + "你好,线程[" + Thread.currentThread().getName() + "]执行方法hello03()完毕,有参数无返回数据,异步执行");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
1.4 有参数,有返回值
/**
* 有参数,有返回值
*/
private String hello04(String name) {
try {
Thread.sleep(5000);
LOG.info(name + "你好,线程[" + Thread.currentThread().getName() + "]执行方法hello04()完毕,有参数有返回数据,需等待线程执行完毕");
} catch (InterruptedException e) {
e.printStackTrace();
}
return "我返回的是" + name + "的数据";
}
二、线程池调用
2.1 无参数,无返回值
/**
* 无参数,且不接收返回数据(无需等待线程执行完毕再执行后续业务,也就是异步执行)
* execute(Runnable command):
* 将一个Runnable任务提交给线程池执行。该方法将会在ThreadPoolExecutor内部的阻塞队列中插入任务,等待线程池中的线程执行任务。
*/
public void test01(){
ExecutorSerDemo es = new ExecutorSerDemo();
ExecutorService executorService = Executors.newFixedThreadPool(3);
for (int i = 0; i < 5; i++) {
// 使用匿名内部类的方式创建一个实现了Runnable接口的对象,并在run()方法中调用es.hello01()方法
// executorService.execute(new Runnable() {
// @Override
// public void run() {
// es.hello01();
// }
// });
// 建议使用Lambda表达式的方式,更加简洁易读
executorService.execute(() -> es.hello01());
}
executorService.shutdown();
System.out.print("test01()执行完毕,");
}
执行结果,先输出了执行用时,线程还在异步执行:
2.2 无参数,有返回值
/**
* 无参数,接收返回数据(需等待线程执行完毕并继续执行后续业务)
*/
public void test02() {
ExecutorSerDemo es = new ExecutorSerDemo();
ExecutorService executorService = Executors.newFixedThreadPool(3);
List<Future<String>> list = new ArrayList<>();
for (int i = 0; i < 5; i++) {
// executorService.submit可以接收返回结果
Future<String> submit = executorService.submit(()->es.hello02());
list.add(submit);
}
List<String> dataList = new ArrayList<>();
try {
// 接收返回数据
for (Future<String> future : list) {
String str = future.get();
dataList.add(str);
}
} catch (Exception e) {
// 如果发生异常则结束所有线程
for (Future<?> future : list) {
future.cancel(true);
}
}
// 关闭线程池
executorService.shutdown();
for (int i = 0; i < dataList.size(); i++) {
System.err.println("接收到的数据:" + dataList.get(i));
}
System.out.print("test02()执行完毕,");
}
执行结果,等待线程执行结束并获取返回结果,再输出执行用时:
2.3 有参数,无返回值
/**
* 有参数,但不接收返回数据(无需等待线程执行完毕再执行后续业务,也就是异步执行)
*/
public void test03() {
List<String> nameList = new ArrayList<>();
nameList.add("小橙");
nameList.add("小红");
nameList.add("小青");
nameList.add("小白");
nameList.add("小紫");
ExecutorSerDemo es = new ExecutorSerDemo();
ExecutorService executorService = Executors.newFixedThreadPool(3);
for (int i = 0; i < nameList.size(); i++) {
// executorService.submit可以接收返回结果
int num = i;
executorService.execute(()->es.hello03(nameList.get(num)));
}
// 关闭线程池
executorService.shutdown();
System.out.print("test03()执行完毕,");
}
执行结果,先输出了执行用时,线程还在异步执行:
2.4 有参数,有返回值
/**
* 有参数,接收返回数据,等待线程执行完毕再继续执行后续业务
*/
public void test04() {
List<String> nameList = new ArrayList<>();
nameList.add("张三");
nameList.add("李四");
nameList.add("王五");
nameList.add("赵六");
nameList.add("林七");
ExecutorSerDemo es = new ExecutorSerDemo();
ExecutorService executorService = Executors.newFixedThreadPool(3);
List<Future<String>> list = new ArrayList<>();
for (int i = 0; i < nameList.size(); i++) {
// executorService.submit可以接收返回结果
int num = i;
Future<String> submit = executorService.submit(()->es.hello04(nameList.get(num)));
list.add(submit);
}
List<String> dataList = new ArrayList<>();
try {
// 接收返回数据
for (Future<String> future : list) {
String str = future.get();
dataList.add(str);
}
} catch (Exception e) {
for (Future<?> future : list) {
future.cancel(true);
}
}
// 关闭线程池
executorService.shutdown();
for (int i = 0; i < dataList.size(); i++) {
System.err.println(dataList.get(i));
}
System.out.print("test04()执行完毕,");
}
执行结果,等待线程执行结束并获取返回结果,再输出执行用时:
三、总结
3.1 不接收返回值
使用:
executorService.execute()
3.2 接收返回值
使用:
executorService.submit()
3.3 不需要等待线程执行结果(异步)
使用:
executorService.execute()
3.4 需要等待线程执行结果(阻塞)
使用:
executorService.submit()
四、测试类
代码如下:
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.util.StopWatch;
public class ExecutorSerDemo {
private static final Logger LOG = LogManager.getLogger();
public static void main(String[] args) {
ExecutorSerDemo es = new ExecutorSerDemo();
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// es.test01();
// es.test02();
// es.test03();
es.test04();
stopWatch.stop();
// 统计用时
long[] de = formatDurationByMillis(stopWatch.getTotalTimeMillis());
System.out.println("用时:" + de[0] + "天" + de[1] + "小时" + de[2] + "分" + de[3] + "秒" + de[4] + "毫秒");
}
/**
* 无参数,且不接收返回数据(无需等待线程执行完毕再执行后续业务,也就是异步执行)
* execute(Runnable command):
* 将一个Runnable任务提交给线程池执行。该方法将会在ThreadPoolExecutor内部的阻塞队列中插入任务,等待线程池中的线程执行任务。
*/
public void test01(){
ExecutorSerDemo es = new ExecutorSerDemo();
ExecutorService executorService = Executors.newFixedThreadPool(3);
for (int i = 0; i < 5; i++) {
// 使用匿名内部类的方式创建一个实现了Runnable接口的对象,并在run()方法中调用es.hello01()方法
// executorService.execute(new Runnable() {
// @Override
// public void run() {
// es.hello01();
// }
// });
// 建议使用Lambda表达式的方式,更加简洁易读
executorService.execute(() -> es.hello01());
}
executorService.shutdown();
System.out.print("test01()执行完毕,");
}
/**
* 无参数,接收返回数据(需等待线程执行完毕并继续执行后续业务)
*/
public void test02() {
ExecutorSerDemo es = new ExecutorSerDemo();
ExecutorService executorService = Executors.newFixedThreadPool(3);
List<Future<String>> list = new ArrayList<>();
for (int i = 0; i < 5; i++) {
// executorService.submit可以接收返回结果
Future<String> submit = executorService.submit(()->es.hello02());
list.add(submit);
}
List<String> dataList = new ArrayList<>();
try {
// 接收返回数据
for (Future<String> future : list) {
String str = future.get();
dataList.add(str);
}
} catch (Exception e) {
// 如果发生异常则结束所有线程
for (Future<?> future : list) {
future.cancel(true);
}
}
// 关闭线程池
executorService.shutdown();
for (int i = 0; i < dataList.size(); i++) {
System.err.println("接收到的数据:" + dataList.get(i));
}
System.out.print("test02()执行完毕,");
}
/**
* 有参数,但不接收返回数据(无需等待线程执行完毕再执行后续业务,也就是异步执行)
*/
public void test03() {
List<String> nameList = new ArrayList<>();
nameList.add("小橙");
nameList.add("小红");
nameList.add("小青");
nameList.add("小白");
nameList.add("小紫");
ExecutorSerDemo es = new ExecutorSerDemo();
ExecutorService executorService = Executors.newFixedThreadPool(3);
for (int i = 0; i < nameList.size(); i++) {
// executorService.submit可以接收返回结果
int num = i;
executorService.execute(()->es.hello03(nameList.get(num)));
}
// 关闭线程池
executorService.shutdown();
System.out.print("test03()执行完毕,");
}
/**
* 有参数,接收返回数据,等待线程执行完毕再继续执行后续业务
*/
public void test04() {
List<String> nameList = new ArrayList<>();
nameList.add("张三");
nameList.add("李四");
nameList.add("王五");
nameList.add("赵六");
nameList.add("林七");
ExecutorSerDemo es = new ExecutorSerDemo();
ExecutorService executorService = Executors.newFixedThreadPool(3);
List<Future<String>> list = new ArrayList<>();
for (int i = 0; i < nameList.size(); i++) {
// executorService.submit可以接收返回结果
int num = i;
Future<String> submit = executorService.submit(()->es.hello04(nameList.get(num)));
list.add(submit);
}
List<String> dataList = new ArrayList<>();
try {
// 接收返回数据
for (Future<String> future : list) {
String str = future.get();
dataList.add(str);
}
} catch (Exception e) {
for (Future<?> future : list) {
future.cancel(true);
}
}
// 关闭线程池
executorService.shutdown();
for (int i = 0; i < dataList.size(); i++) {
System.err.println(dataList.get(i));
}
System.out.print("test04()执行完毕,");
}
// ------------------- private method -------------------
/**
* 无参数,无返回值
*/
private void hello01() {
try {
Thread.sleep(5000);
LOG.info("线程[" + Thread.currentThread().getName() + "]执行方法hello01()完毕,无参数无返回数据,异步执行");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 无参数,有返回值
*/
private String hello02() {
try {
Thread.sleep(3000);
LOG.info("线程[" + Thread.currentThread().getName() + "]执行方法hello02()完毕,无参数有返回数据,需等待线程执行完毕");
} catch (InterruptedException e) {
e.printStackTrace();
}
// 返回随意的一串字符串
return "我返回的是随机字符串:" + UUID.randomUUID().toString();
}
/**
* 有参数,无返回值
*/
private void hello03(String name) {
try {
Thread.sleep(5000);
LOG.info(name + "你好,线程[" + Thread.currentThread().getName() + "]执行方法hello03()完毕,有参数无返回数据,异步执行");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 有参数,有返回值
*/
private String hello04(String name) {
try {
Thread.sleep(5000);
LOG.info(name + "你好,线程[" + Thread.currentThread().getName() + "]执行方法hello04()完毕,有参数有返回数据,需等待线程执行完毕");
} catch (InterruptedException e) {
e.printStackTrace();
}
return "我返回的是" + name + "的数据";
}
/**
* <h5>功能:根据毫秒数来格式化持续时间</h5>
*
* @param millis 毫秒数
* @return long[] 返回值为:{天, 时, 分, 秒, 毫秒}
*/
private static long[] formatDurationByMillis(long millis) {
long day = TimeUnit.MILLISECONDS.toDays(millis);
long hour = TimeUnit.MILLISECONDS.toHours(millis) % 24;
long minute = TimeUnit.MILLISECONDS.toMinutes(millis) % 60;
long seconds = TimeUnit.MILLISECONDS.toSeconds(millis) % 60;
millis = millis % 1000;
long[] times = { day, hour, minute, seconds, millis };
return times;
}
}
五、应用
将一个大的集合分割成多个小集合,然后使用线程池并发执行,可以有效减少总体用时时间。List数据分割可以参考《List集合分组(大List分割成多个小List)》
public void test(List<Map<String, Object>> maps) {
List<Future<Boolean>> list = new ArrayList<>();
System.out.println("多线程任务执行开始");
// 将List集合进行分组
List<List<Map<String, Object>>> dataList = splitList(maps, 20);
if (!dataList.isEmpty()) {
ExecutorService service = Executors.newFixedThreadPool(threadCount);
for (int i = 0; i < dataList.size(); i++) {
int k = i;
Future<Boolean> submit = service.submit(() -> selectAll(dataList.get(k)));
list.add(submit);
}
for (Future<Boolean> future : list) {
future.get();
future.cancel(true);
}
service.shutdown();
}
System.out.println("多线程任务执行完毕");
}
/**
* <h5>描述:将List集合进行分组<h5>
*/
private static <T> List<List<T>> splitList(List<T> oldList, int batchSize) {
if (batchSize < 1) {
return null;
}
List<List<T>> result = new ArrayList<>();
int size = oldList.size();
int count = (size + batchSize - 1) / batchSize;
for (int i = 0; i < count; i++) {
int fromIndex = i * batchSize;
int toIndex = (i + 1) * batchSize > size ? size : (i + 1) * batchSize;
List<T> subList = oldList.subList(fromIndex, toIndex);
result.add(subList);
}
return result;
}