Future主要功能在于获取任务执行结果和对异步任务的控制。但如果要获取批量任务的执行结果,从上面的例子我们已经可以看到,单使用 Future 是很不方便的。其主要原因在于:一方面是没有好的方法去判断第一个完成的任务;另一方面是 Future的get方法 是阻塞的,使用不当会造成线程的浪费。第一个问题可以用 CompletionService 解决, CompletionService 提供了一个 take() 阻塞方法,用以依次获取所有已完成的任务。 第二个问题可以用 Google Guava 库所提供的 ListeningExecutorService 和 ListenableFuture 来解决。除了获取批量任务执行结果时不便,Future另外一个不能做的事便是防止任务的重复提交。要做到这件事就需要 Future 最常见的一个实现类 FutureTask 了。Future只实现了异步,而没有实现回调,主线程get时会阻塞,可以轮询以便获取异步调用是否完成。
在实际的使用中建议使用Guava ListenableFuture来实现异步非阻塞,目的就是多任务异步执行,通过回调的方方式来获取执行结果而不需轮询任务状态。
import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.Executors; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; public class ListenableTest { public static void main(String[] args) { ListeningExecutorService executorService = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool()); final List<Long> value = new ArrayList<Long>(); List<ListenableFuture<Long>> futures = new ArrayList<ListenableFuture<Long>>(); for(long i=1;i<=3;i++){ // 处理线程逻辑 final ListenableFuture<Long> listenableFuture = executorService.submit(new AddCallable(1000000*(i-1)+1,i*1000000)); // 回调方法 Futures.addCallback(listenableFuture, new FutureCallback<Long>() { @Override public void onSuccess(Long result) { value.add(result); } @Override public void onFailure(Throwable t) { t.printStackTrace(); } }); futures.add(listenableFuture); } // 阻塞三个线程执行完成 Futures.allAsList(futures); long result = 0 ; for(int i=0,n=value.size();i<n;i++){ result += value.get(i); } System.out.println("sum:"+result); executorService.shutdownNow(); } } /** * 累加线程 * @author * @time */ class AddCallable implements Callable<Long>{ private long begin ; private long end ; public AddCallable(long begin,long end){ this.begin = begin ; this.end = end ; } @Override public Long call() throws Exception { long result = 0; for(long i=begin;i<=end;i++){ result += i; } return result ; } }