CompletionService 簡介

        當向Executor提交批處理任務時,而且但願在它們完成後得到結果,若是用FutureTask,你能夠循環獲取task,並用future.get()去獲取結果,可是若是這個task沒有完成,你就得阻塞在這裏,這個實效性不高,其實在不少場合,其實你拿第一個任務結果時,此時結果並無生成並阻塞,其實在阻塞在第一個任務時,第二個task的任務已經早就完成了,顯然這種狀況用future task不合適的,效率也不高。
       本身維護list和CompletionService的區別: java

  1. 從list中遍歷的每一個Future對象並不必定處於完成狀態,這時調用get()方法就會被阻塞住,若是系統是設計成每一個線程完成後就能根據其結果繼續作後面的事,這樣對於處於list後面的可是先完成的線程就會增長了額外的等待時間。
  2. 而CompletionService的實現是維護一個保存Future對象的BlockingQueue。只有當這個Future對象狀態是結束的時候,纔會加入到這個Queue中,take()方法其實就是Producer-Consumer中的Consumer。它會從Queue中取出Future對象,若是Queue是空的,就會阻塞在那裏,直到有完成的Future對象加入到Queue中。
       CompletionService採起的是BlockingQueue<Future<V>>無界隊列來管理Future。則有一個線程執行完畢把返回結果放到BlockingQueue<Future<V>>裏面。就能夠經過completionServcie.take().get()取出結果。

         方法區別: app

  • take 方獲取並移除表示下一個已完成任務的 Future,若是目前不存在這樣的任務,則等待。<若是須要用到返回值建議用take>
  • poll 獲取並移除表示下一個已完成任務的 Future,若是不存在這樣的任務,則返回null。

如下是jdk關於CompletionService的簡介: dom

  •    public interface CompletionService<V>
  • 將生產新的異步任務與使用已完成任務的結果分離開來的服務。生產者 submit 執行的任務。使用者 take 已完成的任務,並按照完成這些任務的順序處理它們的結果。例如,CompletionService 能夠用來管理異步 IO ,執行讀操做的任務做爲程序或系統的一部分提交,而後,當完成讀操做時,會在程序的不一樣部分執行其餘操做,執行操做的順序可能與所請求的順序不一樣。
  • 一般,CompletionService 依賴於一個單獨的 Executor 來實際執行任務,在這種狀況下,CompletionService 只管理一個內部完成隊列。ExecutorCompletionService 類提供了此方法的一個實現。 
  • 內存一致性效果:線程中向 CompletionService 提交任務以前的操做 happen-before 該任務執行的操做,後者依次 happen-before 緊跟在從對應 take() 成功返回的操做。 

廢話少說,直接看代碼: 異步

package com.lucky.concurrent;

import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CompletionServiceDemo {

	public static class Task implements Callable<Integer> {
		private int i;

		Task(int i) {
			this.i = i;
		}

		@Override
		public Integer call() throws Exception {
			Thread.sleep(new Random().nextInt(5000));
			System.out.println(Thread.currentThread().getName() + "   " + i);
			return i;
		}
	}

	public void run() {
		ExecutorService pool = Executors.newFixedThreadPool(10);
		CompletionService<Integer> completionServcie = new ExecutorCompletionService<Integer>(
				pool);
		try {
			for (int i = 0; i < 10; i++) {
				completionServcie.submit(new CompletionServiceDemo.Task(i));
			}
			for (int i = 0; i < 10; i++) {
				// take 方法等待下一個結果並返回 Future 對象。
				// poll 不等待,有結果就返回一個 Future 對象,不然返回 null。
				System.out.println(completionServcie.take().get());
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		} finally {
			pool.shutdown();
		}
	}

	public static void main(String[] args) {
		new CompletionServiceDemo().run();
	}
}
直接結果:


從結果中不難看出。只要有一個線程執行完畢後,主程序就立馬獲取結果。 ide

相關文章
相關標籤/搜索