- 将一个执行器服务作为线程池使用,以提高执行任务的效率。有时,使用执行器有更有实际意义的原因,控制一组相关任务。例如,可以在执行器中使用
shutdownNow
方法取消所有的任务。 invokeAny
方法提交所有对象到一个Callable
对象的集合中,并返回某个已经完成了的任务的结果。无法知道返回的究竟是哪个任务的结果。invokeAll
方法提交所有对象到一个Callable对象的集合中,并返回一个Future对象的列表,代表所有任务的解决方案。
List<Callable<T>> tasks = ...;
ExecutorService executor = Executors.newCachedThreadPool();
try {
List<Future<T>> futures = executor.invokeAll(tasks);
for(Future<T> result:results){
processFurther(result.get());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
- 这个方法的缺点是如果第一个任务恰巧花去了很多时间,则可能不得不进行等待。将结果按可获得的顺序保存起来更有实际意义。可以用
ExecutorCompletionService
来进行排列。 - 用常规的方法获得一个执行器。然后,构建一个
ExecutorCompletionService
,提交任务给完成服务。该服务管理Future
对象的阻塞队列,其中包含已经提交的任务的执行结果。这样一来,相比前面的计算,一个更有效的组织形式如下:
List<Callable<T>> tasks = new ArrayList<Callable<T>>();
ExecutorService executor = Executors.newCachedThreadPool();
ExecutorCompletionService<Object> service =
new ExecutorCompletionService<>(executor);
for(Callable<T> task : tasks){
service.submit(task);
}
for (int i =0;i<((ArrayList) tasks).size();i++){
try {
//take 检索并删除此队列的头部,必要时等待直到元素可用
processFuther(service.take().get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}