ExecutorCompletionService 使用及其源码分析

作用

“既生 ExecutorService, 何生 CompletionService?” - SegmentFault 思否

案例

public static void main(String[] args) throws InterruptedException, ExecutionException {  

    ExecutorService executorService = Executors.newFixedThreadPool(4);  
    // ExecutorCompletionService 是 CompletionService 唯一实现类  
    CompletionService executorCompletionService= new ExecutorCompletionService<>(executorService);  
  
    List<Future<Integer>> futures = new ArrayList<Future<Integer>>();  
    futures.add(executorCompletionService.submit(()->{  
        TimeUnit.SECONDS.sleep(4);  
        return 1;  
    }));  
    futures.add(executorCompletionService.submit(()->{  
        TimeUnit.SECONDS.sleep(3);  
        return 2;  
    }));  
    futures.add(executorCompletionService.submit(()->{  
        TimeUnit.SECONDS.sleep(2);  
        return 3;  
    }));  
    futures.add(executorCompletionService.submit(()->{  
        TimeUnit.SECONDS.sleep(1);  
        return 4;  
    }));  
  
    // 遍历 Future list,通过 get() 方法获取每个 future 结果  
    for (int i=0; i<futures.size(); i++) {  
        Future<Integer> f = executorCompletionService.take();  
        Integer integer = f.get();  
        System.out.println(integer);  
        // 其他业务逻辑  
    }  
}

//输出:
4
3
2
1

源码分析

主要属性


//执行任务的线程池
private final Executor executor;  
//aes 主要是用于newTaskFor方法用于生成FutureTask对象,作用不是很大,可以为null
private final AbstractExecutorService aes;  
//队列,主要用于存放完成了(done)的Future对象
private final BlockingQueue<Future<V>> completionQueue;

构造方法

// 传入一个线程池,负责执行任务
public ExecutorCompletionService(Executor executor) {  
    if (executor == null)  
        throw new NullPointerException();  
    this.executor = executor;  
    //这个aes属性作用不是很核心,可以忽略,可以为null,不影响使用
    this.aes = (executor instanceof AbstractExecutorService) ?  
        (AbstractExecutorService) executor : null;  
    //队列默认是LinkedBlockingQueue
    this.completionQueue = new LinkedBlockingQueue<Future<V>>();  
}

//传入一个线程池,一个队列,队列不写默认是无界队列LinkedBlockingQueue
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;  
}
                    

ase属性的作用

private RunnableFuture<V> newTaskFor(Callable<V> task) {  
	//如果ase属性为null,就自己手动构造一个FutureTask
    if (aes == null)  
        return new FutureTask<V>(task);  
    else        
	    //不为空就调用aes的newTaskFor方法
	    return aes.newTaskFor(task);  
}


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

内部类

//重写了FutureTask,主要是重写了done方法
private class QueueingFuture extends FutureTask<Void> {  
    QueueingFuture(RunnableFuture<V> task) {  
        super(task, null);  
        this.task = task;  
    }  
    //关键点设计:重写了done方法,done方法是任务完成后的回调。这里任务完成后会自动放入队列completionQueue
    protected void done() { completionQueue.add(task); }  
    private final Future<V> task;  
}

submit方法

public Future<V> submit(Callable<V> task) {  
    if (task == null) throw new NullPointerException();  
    RunnableFuture<V> f = newTaskFor(task);  
    //executor来真正干活,活生生的工具人
    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;  
}

获取完成的任务

//如果队列为空,会阻塞队列,是阻塞队列的api
public Future<V> take() throws InterruptedException {  
    return completionQueue.take();  
}  
//检索,删除队列的头。队列为空,则返回 null 
public Future<V> poll() {  
    return completionQueue.poll();  
}  
//超时,返回null
public Future<V> poll(long timeout, TimeUnit unit)  
        throws InterruptedException {  
    return completionQueue.poll(timeout, unit);  
}

设计特点

  • 引入阻塞队列属性completionQueue 来存放完成的任务。
  • 通过实现内部类QueueingFuture,重写done方法,实现任务完成回调,把完成的任务入队列。
  • 通过以上,来实现先完成的任务先入队列。使用的时候,调用队列的take方法即可拿到先完成的任务。

思考

  • 第一
    这个ExecutorCompletionService一般是不能业务混用。业务A自己作用域下初始化一个,业务B自己作用域初始化一个。如果混用,那么业务A take方法得到的Futrue很有可能是业务B提交的任务。
  • 第二
    • 从案例的返回结果可以看出,如果在意返回结果的顺序跟提交的顺序一致,那么ExecutorCompletionService不适合该场景。请用传统的线程池提交任务。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值