分享一篇關於Java中ExecutorService和CompletionService區別,有須要的朋友能夠參考一下。java
咱們如今在Java中使用多線程一般不會直接用Thread對象了,而是會用到java.util.concurrent包下的ExecutorService類來初始化一個線程池供咱們使用。多線程
以前我一直習慣本身維護一個list保存submit的callable task所返回的Future對象。線程
在主線程中遍歷這個list並調用Future的get()方法取到Task的返回值。設計
可是,我在不少地方會看到一些代碼經過CompletionService包裝ExecutorService,而後調用其take()方法去取Future對象。之前沒研究過這二者之間的區別。對象
今天看了源代碼以後就明白了。get
這二者最主要的區別在於submit的task不必定是按照加入本身維護的list順序完成的。it
從list中遍歷的每一個Future對象並不必定處於完成狀態,這時調用get()方法就會被阻塞住,若是系統是設計成每一個線程完成後就能根據其結果繼續作後面的事,這樣對於處於list後面的可是先完成的線程就會增長了額外的等待時間。io
而CompletionService的實現是維護一個保存Future對象的BlockingQueue。只有當這個Future對象狀態是結束的時候,纔會加入到這個Queue中,take()方法其實就是Producer-Consumer中的Consumer。它會從Queue中取出Future對象,若是Queue是空的,就會阻塞在那裏,直到有完成的Future對象加入到Queue中。線程池