java concurrent之CompletionService

    在采用Executor执行任务时,可用通过采用Future来获取单个任务执行的结果,在Future中提供了一个get方法,该方法在任务执行返回之前,将会阻塞。

当向Executor提交批处理任务时,并且希望在它们完成后获得结果,如果用FutureTask,你可以针对这一组任务进行遍历,并用future.get()去获取结果,若当前任务没有完成,则会造成阻塞。这对于对任务结果需要分别对待的时候是可行的。但是若所有task产生的结果都可以被同等看待,这时候遍历这样的方式显然是不可行了,因为遍历时,后访问的future的任务先于当前访问的任务,由于future.get()方法是阻塞的,因此需要等待当前任务完成才能继续后面的遍历,这样的话就会导致实效性不高。

显然很多时候,一组task产生的结果都应该是没有区别的,也就是满足上述第二种情况。这个时候咋办呢?jdk为我们提供了一个很好的接口CompletionService
这个接口的具体实现类是ExecutorCompletionService。
该类中定义下面三个属性
private final Executor executor;
private final AbstractExecutorService aes;
private final BlockingQueue<Future<V>> completionQueue;
executor由构造函数传入,aes只是用于生成Future对象。特别要注意是completionQueue。
它维护了一个保存Future对象的BlockingQueue。当这个Future对象状态是结束的状态的时候,也就是task执行完成之后,会将它加入到这个Queue中。到底是在哪里将完成的Future加入到队列里面的呢?又是怎么知道task是什么时候结束的呢?
在ExecutorCompletionService中定义了一个QueueingFuture类,该类的实现:

private class QueueingFuture extends FutureTask<Void> {
        QueueingFuture(RunnableFuture<V> task) {
            super(task, null);
            this.task = task;
        }
        protected void done() { completionQueue.add(task); }
        private final Future<V> task;
    }

可以看到在done方法中,它会把当前的task加入到阻塞队列中。
追踪done方法可以看到,该方法定义在FutureTask中,默认实现为空,从注释可以看出,当Future的状态转为isDone的时候,就会调用该方法。

调用端在调用CompletionService的take方法时,实际上调用的是BlockingQueue的take方法,当队列中有内容时,该方法会会立即返回队列中的对象,当队列为空时,调用线程将会阻塞。而只要有任务完成,调用线程就会跳出阻塞,获得结果。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值