【詳解】Executors框架之CompletionService

Future的缺點

雖然Future可以異步的執行任務,但是還是有很多缺點:

  • 沒有辦法回調,需要手動的調用
  • 執行一組任務需要等待所有的任務執行完

CompletionService簡介

CompletionService的實現目標是任務先完成可優先獲取到,即結果按照完成先後順序排序。

ExecutorCompletionService類,該類只有三個成員變量:

public class ExecutorCompletionService<V> implements CompletionService<V> {
    private final Executor executor;
    private final AbstractExecutorService aes;
    private final BlockingQueue<Future<V>> completionQueue;
    ....
}
  • 可以看到ExecutorCompletionService主要是增強executor線程池的。
  • Task包裝後被塞入completionQueue,當Task結束,其Future就可以從completionQueue中獲取到。

執行流程爲
在這裏插入圖片描述

基本使用

public class CompletionServiceTest {

    public static void main(String[] args)  {
        Long start = System.currentTimeMillis();
        //開啓3個線程
        ExecutorService exs = Executors.newFixedThreadPool(5);
        try {
            int taskCount = 10;
            // 結果集
            List<Integer> list = new ArrayList<Integer>();

            // 1.定義CompletionService
            CompletionService<Integer> completionService = new ExecutorCompletionService<Integer>(exs);

            // 2.添加任務
            for(int i=0;i<taskCount;i++){
                completionService.submit(new Task(i+1));
            }

            // 3.獲取結果
            for(int i=0;i<taskCount;i++){
                Integer result = completionService.take().get();
                list.add(result);
            }

            System.out.println("list="+list);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //關閉線程池
            exs.shutdown();
        }

    }

    static class Task implements Callable<Integer> {
        Integer i;

        public Task(Integer i) {
            super();
            this.i=i;
        }

        @Override
        public Integer call() throws Exception {
            if(i==5) {
                Thread.sleep(5000);
            }else{
                Thread.sleep(1000);
            }
            System.out.println("線程:"+Thread.currentThread().getName()+"任務i="+i+",執行完成!");
            return i;
        }

    }
}

結果

線程:pool-1-thread-1任務i=1,執行完成!
線程:pool-1-thread-2任務i=2,執行完成!
線程:pool-1-thread-3任務i=3,執行完成!
線程:pool-1-thread-4任務i=4,執行完成!
線程:pool-1-thread-1任務i=7,執行完成!
線程:pool-1-thread-3任務i=8,執行完成!
線程:pool-1-thread-4任務i=9,執行完成!
線程:pool-1-thread-2任務i=6,執行完成!
線程:pool-1-thread-1任務i=10,執行完成!
線程:pool-1-thread-5任務i=5,執行完成!
list=[1, 2, 3, 4, 7, 8, 9, 6, 10, 5]
  • 可以發現結果順序就是任務完成的順序

阻塞和非阻塞獲取

public Future<V> take()throws InterruptedException

public Future<V> poll()
public Future<V> poll(long timeout,TimeUnit unit) throws InterruptedException

阻塞獲取

take方法回使調用者阻塞,可以保證一定會有Future取出

非阻塞獲取

poll方法會去查看是否有任務完成,有則取出;沒有,就會返回一個null

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章