关于ExecutorService的Future的误解

一.概述

在多线程编程中我们经常使用ExecutorService的Future来实现等待多个线程返回的需求。此时需要调用ExecutorService的相关方法来实现,比如

1
2
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
        throws InterruptedException;

调用这个方法后,遍历返回的List就能获取到本次新增tasks的返回值,要是某个task执行时间较长,调用Future的get方法就会阻塞,当然你也可以选择使用能设置超时时间的get方法。

Future的get方法,一个可以设置超时时间,一个不能设置超时时间。

1
2
3
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;

这样我们就能等所有线程都返回后,然后继续做相关的计算逻辑。

二.常常被误解的地方

我们在一个线程池A上调用下面的方法

1
2
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
        throws InterruptedException;

假设在调用这个方法之前线程池中有M个线程在RUNNING,调用这个方法后又往线程池中增加了N个线程,然后遍历返回的List,此时返回的List中只会包含后面加入的N个线程,而不会包含前面已经存在的M个线程,因此List的大小是N,不是M+N,经常会有人误以为是M+N。因此当遇到需要N个线程都返回后才继续向下的场景时,就放心大胆的使用Future吧。