关于线程池就不做太多介绍,相关文章有很多,本文重点是记录自己测试线程池+Callable+FutureTask实现多线程的代码,大家可以参考参考;
public class threadPoolTestService {
public void test(){
//创建线程池
ExecutorService executorService = Executors.newFixedThreadPool(5);
//线程安全的AtomicInteger,后续多线程减少数据
AtomicInteger atomicInteger = new AtomicInteger(20);
//创建一个线程安全的集合
CopyOnWriteArrayList<FutureTask<Integer>> integers = new CopyOnWriteArrayList<>();
//记录一个开始时间
long start = System.currentTimeMillis();
//for循环调用多线程执行任务
for (int i = 0; i < 10; i++) {
//返回结果是异步的,线程执行,就会返回,只不过没有具体数据
FutureTask<Integer> integerFutureTask = new FutureTask<>(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
System.out.println(Thread.currentThread().getName() + "--------");
//方法执行2s
Thread.sleep(2000);
//数据减1
return atomicInteger.getAndDecrement();
}
});
//执行任务
executorService.submit(integerFutureTask);
//封装结果
integers.add(integerFutureTask);
}
//处理多线程执行的结果集
for (FutureTask<Integer> integer : integers) {
try {
//注意,futureTask的get方法,会导致线程阻噻,也就会等待任务执行完毕,获取结果
System.out.println(integer.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
long end = System.currentTimeMillis();
System.out.println("耗时:"+(end-start));
}
}
控制台输出:
显然,总共有5个线程工作,数字从20减到11;
注意:Future和FutureTask的get()方法,是会阻塞的,如果上述部分代码更改成如下所示(在for循环里面调用了FutureTask.get()方法)
//集合更改为Integer类型,不再是FutureTask类型
CopyOnWriteArrayList<Integer> integers = new CopyOnWriteArrayList<>();
//记录一个开始时间
long start = System.currentTimeMillis();
//for循环调用多线程执行任务
for (int i = 0; i < 10; i++) {
//返回结果是异步的,线程执行,就会返回,只不过没有具体数据
FutureTask<Integer> integerFutureTask = new FutureTask<>(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
System.out.println(Thread.currentThread().getName() + "--------");
//方法执行2s
Thread.sleep(2000);
//数据减1
return atomicInteger.getAndDecrement();
}
});
//执行任务
executorService.submit(integerFutureTask);
//封装结果,调用get()方法
integers.add(integerFutureTask.get());
}
结果将变成
显然,耗时20040比原来的4016要大很多,虽然输出里面显示有5个线程在工作,但是都是等上一个线程执行结束,下一个线程才开始执行,基本就和单线程无异了;
这是因为我们在for循环里面调用了FutureTask.get()方法,该方法会等待当前线程把代码执行完拿到返回结果才终止;而我们开启下一个线程的前提是当前循环结束,进入下一次循环才会开启新的线程;这样新线程开启的时候,上一个线程都已经完全执行结束了,所以就和单线程无异了,导致耗时很长;