用例表示不同型別的併發結構

  1. ExecutorService 的

    ExecutorService executor = Executors.newFixedThreadPool(50);

    它簡單易用。它隱藏了 ThreadPoolExecutor 的低階細節。

    Callable/Runnable 任務的數量很少並且在無界佇列中堆積任務不會增加記憶體並降低系統效能時,我更喜歡這個。如果你有 CPU/Memory 約束,我更喜歡使用帶有容量限制的 ThreadPoolExecutorRejectedExecutionHandler 來處理任務的拒絕。

  2. CountDownLatch

    CountDownLatch 將使用給定的計數進行初始化。通過呼叫 countDown() 方法減少此計數。等待此計數達到零的執行緒可以呼叫其中一個 await() 方法。呼叫 await() 會阻塞執行緒,直到計數達到零。此類使 java 執行緒等待,直到其他執行緒集完成其任務。

    用例:

    1. 實現最大並行性:有時我們希望同時啟動多個執行緒以實現最大並行度

    2. 在開始執行之前等待 N 個執行緒完成

    3. 死鎖檢測。

  3. ThreadPoolExecutor :它提供更多控制。如果應用程式受到待處理的 Runnable / Callable 任務數量的限制,則可以通過設定最大容量來使用有界佇列。佇列達到最大容量後,你可以定義 RejectionHandler。Java 提供了四種型別的 RejectedExecutionHandler 策略

    1. ThreadPoolExecutor.AbortPolicy,處理程式在拒絕時丟擲執行時 RejectedExecutionException。

    2. ThreadPoolExecutor.CallerRunsPolicy`,呼叫 execute 本身的執行緒執行任務。這提供了一種簡單的反饋控制機制,可以降低新任務的提交速度。

    3. ThreadPoolExecutor.DiscardPolicy 中,簡單地刪除了無法執行的任務。

    4. ThreadPoolExecutor.DiscardOldestPolicy,如果執行程式未關閉,則刪除工作佇列頭部的任務,然後重試執行(可能會再次失敗,導致重複執行)。

如果要模擬 CountDownLatch 行為,可以使用 invokeAll() 方法。

  1. 你沒有引用的一種機制是 ForkJoinPool

    在 Java 7 中將 ForkJoinPool 新增到 Java 中 .ForkJoinPool 類似於 Java ExecutorService,但有一點不同。ForkJoinPool 使任務很容易將他們的工作分成更小的任務,然後提交給 ForkJoinPool。當自由工作執行緒從繁忙的工作執行緒佇列中竊取任務時,任務竊取發生在 ForkJoinPool 中。

    Java 8 在 ExecutorService 中引入了另外一個 API 來建立工作竊取池。你不必建立 RecursiveTaskRecursiveAction,但仍然可以使用 ForkJoinPool

    public static ExecutorService newWorkStealingPool()
    

    使用所有可用處理器作為其目標並行級別建立工作竊取執行緒池。

    預設情況下,它會將 CPU 核心數作為引數。

所有這四種機制互為補充。根據你要控制的粒度級別,你必須選擇正確的粒度級別。