线程池原理(五):CompletionService

任务提交到线程池后,将任务的Future放到一个List中,然后遍历List,通过Future的get方法得到返回值。如果在遍历过程中get方法阻塞,即使位于List后面的Future已经完成,遍历List的线程也要继续等待,这就对效率有比较大的影响。我们希望任务结束后,返回值能够立即被获取,而不是要等待其他任务结束。

CompletionService正是为此而生,实现中通过维护一个队列保存结束任务的Future,如果有任务结束,任务的Future会保存到队列中,从该队列中一定能拿到任务的返回结果。如果没有已经完成的任务,队列为空,取结果的线程会阻塞。

CompletionService

我们先看下接口CompletionService

public interface CompletionService<V> {
    //提交任务
    Future<V> submit(Callable<V> task);

    //提交任务
    Future<V> submit(Runnable task, V result);

    //取下一个已经结束任务的返回值,如果没有则等待
    //注意,该方法响应中断
    Future<V> take() throws InterruptedException;

    //取下一个已经结束任务的返回值,如果没有返回null
    Future<V> poll();

    //取下一个已经结束任务的返回值,如果没有最多等待timeout时间
    Future<V> poll(long timeout, TimeUnit unit) throws InterruptedException;
}

该接口很简单,主要就是take、pool方法,取已经完成任务的返回值,接着我们看下jdk中该接口的实现类,ExecutorCompletionService。

ExecutorCompletionService

该类实现了CompletionService,维护一个阻塞队列(默认为LinkedBlockingQueue)保存已经完成的任务Future。worker执行完某个任务时会将任务的Future添加到该阻塞队列,阻塞队列按任务的完成顺序保存了任务的Future。取任务时,如果阻塞队列为空,说明没有已经完成的任务。看下该该类的实现:

public class ExecutorCompletionService<V> implements CompletionService<V> {
    //任务的执行委托给了executor
    private final Executor executor;
    //如果executor继承自AbstractExecutorService,aes和executor指向同一个对象
    //否则aes为空
    private final AbstractExecutorService aes;
    //保存完成任务的Future
    private final BlockingQueue<Future<V>> completionQueue;

    //CompletionService执行的任务继承了FutureTask,重写了done方法
    //每当任务结束后将任务的Future加到completionQueue中
    private class QueueingFuture extends FutureTask<Void> {
        QueueingFuture(RunnableFuture<V> task) {
            super(task, null);
            this.task = task;
        }
        //任务结束后将Future加到队列中
        protected void done() { completionQueue.add(task); }
        private final Future<V> task;
    }

    //包装成FutureTask
    private RunnableFuture<V> newTaskFor(Callable<V> task) {
        if (aes == null)
            return new FutureTask<V>(task);
        else
            return aes.newTaskFor(task);
    }

    //包装成FutureTask
    private RunnableFuture<V> newTaskFor(Runnable task, V result) {
        if (aes == null)
            return new FutureTask<V>(task, result);
        else
            return aes.newTaskFor(task, result);
    }

    //构造函数,指定执行器executor
    public ExecutorCompletionService(Executor executor) {
        if (executor == null)
            throw new NullPointerException();
        this.executor = executor;
        this.aes = (executor instanceof AbstractExecutorService) ?
            (AbstractExecutorService) executor : null;
        //用LinkedBlockingQueue保存完成任务的Future
        this.completionQueue = new LinkedBlockingQueue<Future<V>>();
    }

    //构造函数,指定executor和queue
    public ExecutorCompletionService(Executor executor,
                                     BlockingQueue<Future<V>> completionQueue) {
        if (executor == null || completionQueue == null)
            throw new NullPointerException();
        this.executor = executor;
        this.aes = (executor instanceof AbstractExecutorService) ?
            (AbstractExecutorService) executor : null;
        this.completionQueue = completionQueue;
    }

    //提交任务,将任务包装成QueueingFuture后交给executor执行
    public Future<V> submit(Callable<V> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<V> f = newTaskFor(task);
        executor.execute(new QueueingFuture(f));
        return f;
    }

    public Future<V> submit(Runnable task, V result) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<V> f = newTaskFor(task, result);
        executor.execute(new QueueingFuture(f));
        return f;
    }

    //从队列中取已经结束任务的返回值,如果队列为空则阻塞
    public Future<V> take() throws InterruptedException {
        return completionQueue.take();
    }

    //从队列中取已经结束任务的返回值,如果队列为空返回null
    public Future<V> poll() {
        return completionQueue.poll();
    }

    //从队列中取已经结束任务的返回值,如果超时,返回空
    public Future<V> poll(long timeout, TimeUnit unit)
            throws InterruptedException {
        return completionQueue.poll(timeout, unit);
    }
}

ExecutorCompletionService实现也很简单,主要是QueueingFuture,将QueueingFuture作为任务来执行,QueueingFuture继承FutureTask,重写了done方法。done方法在FutureTask中是一个空方法,留给子类重写。任务完成后会调用done方法,将任务的Future加到队列中。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值