浅析CompletionService

本文详细介绍了如何使用CompletionService来简化多任务处理的过程。通过Executor提交任务并获取结果,利用CompletionService可以实现更优雅的任务管理和结果获取方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       如果向Executor提交了一组计算任务,并且希望在计算完成后获得结果,那么可以保留与每个任务关联的Future,然后反复使用get方法,同时将参数Timeout指定为0,从而通过轮询来判断任务是否完成。这种方法虽然可行,但确繁琐,可以使用CompletionService完成服务。

CompletionService接口定义了5个方法,并且该接口有且只有一个实现类:ExecutorCompletionService。
public interface CompletionService<V> {

    Future<V> submit(Callable<V> task);

    Future<V> submit(Runnable task, V result);

    Future<V> take() throws InterruptedException;

    Future<V> poll();

    Future<V> poll(long timeout, TimeUnit unit) throws InterruptedException;
}
ExecutorCompletionService定义了一个线程安全的队列:completionQueue
private final BlockingQueue<Future<V>> completionQueue;
以及一个私有类: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;
}
这两个东西,就可以看成是CompletionService功能的核心。
    
      QueueingFuture类重写了FutureTask的done()方法,当一个FutureTask完成的时候,就会将该任务放入完成队列completionQueue里,然后通过队列的take()或poll()方法,将已完成的Future取出。

流程如下:
       当使用CompletionService提交一个Callable时,会将该Callable包装成一个FutureTask,最终变成一个QueueingFuture类,然后直接执行该QueueingFuture:
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;
}
private RunnableFuture<V> newTaskFor(Callable<V> task) {
    if (aes == null)
        return new FutureTask<V>(task);
    else
        return aes.newTaskFor(task);
}
       由于QueueingFuture继续了FutureTask并重写了done方法,所以当QueueingFuture执行完成后,会调用其done()方法,也就是将该完成的Future放入任务完成队列里。
       然后可以通过take()或poll()方法取出该已完成的Future。(poll()是非阻塞的,若目前无结果,返回一个null,线程继续运行不阻塞。take()是阻塞的,若当前无结果,则线程阻塞,直到产生一个结果,被取出返回,线程才继续运行。)
public Future<V> take() throws InterruptedException {
    return completionQueue.take();
}

public Future<V> poll() {
    return completionQueue.poll();
}

public Future<V> poll(long timeout, TimeUnit unit)throws InterruptedException {
    return completionQueue.poll(timeout, unit);
}
       这样就达到了一个效果:使用CompletionService提交若干个任务,哪个任务先完成,就先取哪个任务。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值