如果向 Executor 提交了一组计算任务, 并且希望在执行完成后获取结果,可以保存与每个任务关联的 Future ,并调用 get 方法去获取执行结果。但是如果任务还未完成,获取结果的线程将阻塞直到任务完成,由于无法确定任务执行完成的先后循序,使用这种方式效率不高。如果同时将参数 timeout 设置为 0 ,然后循环调用 get 方法,通过轮询来判断任务是否完成。这种方法可行,但是过于繁琐,好在 JDK 提供了一种更好的方法: CompletionService。
CompletionService 源码
CompletionService 接口源码:
1 |
|
目前在 JDK8 中 CompletionService 接口只有一个实现类 ExecutorCompletionService。
ExecutorCompletionService 类内部使用了 Executor 和 BlockingQueue,其中:executor 用于执行任务的线程池,创建 CompletionService 必须指定; aes 主要用于创建待执行任务;completionQueue 存储已完成状态的任务。
1 |
|
ExecutorCompletionService 的2个构造函数,BlockingQueue 默认使用 LinkedBlockingQueue。
1 |
|
当提交某个任务时,该任务将被包装为一个 QueueingFuture,它是 FutureTask 的子类,改写了 done 方法,将完成的任务放入 BlockingQueue 中。
1 |
|
获取已完成任务的方法:
1 |
|
示例
下面看一个使用 CompletionService 实现页面渲染器的例子。为了提高渲染器的性能,将渲染器分解为两个任务,一个渲染所有的文本,一个下载所有的图像。为每一幅图像的下载创建 一个独立的任务。通过从 CompletionService 中获取结果,使每张图片在下载完成后立即显示出来。代码如下:
1 |
|