8

我用Java的執行人在我的多線程應用程序,但我似乎無法找出是最好的使用每個下列方式時:如何正確使用Java執行程序?

1.

ExecutorService executor=Executors.newFixedThreadPool(50); 
executor.execute(new A_Runner(... some parameter ...)); 
executor.shutdown(); 
while (!executor.isTerminated()) { Thread.sleep(100); } 

2 。

int Page_Count=200; 
ExecutorService executor=Executors.newFixedThreadPool(50); 
doneSignal=new CountDownLatch(Page_Count); 
for (int i=0;i<Page_Count;i++) executor.execute(new A_Runner(doneSignal, ... some parameter ...)); 
doneSignal.await(); 
executor.shutdown(); 
while (!executor.isTerminated()) { Thread.sleep(100); } 

3.

int Executor_Count=30; 
ThreadPoolExecutor executor=new ThreadPoolExecutor(Executor_Count,Executor_Count*2,1,TimeUnit.SECONDS,new LinkedBlockingQueue()); 
List<Future<String>> futures=new ArrayList<>(3330); 

for (int i=0;i<50;i++) futures.add(executor.submit(new A_Runner(... some parameter ...)); 
executor.shutdown(); 
while (!executor.isTerminated()) { executor.awaitTermination(1,TimeUnit.SECONDS); } 
for (Future<String> future : futures) 
{ 
    String f=future.get(); 
    // ... 
} 

具體地,在[2],如果我跳過什麼doneSignal,那麼它就像[1],那麼doneSignal有什麼用?

此外,在[3],如果我加入doneSignal?或者可能嗎?

我想知道的是:這些方法可以互換的,或者是有沒有我應該使用上述特定類型的某種情況?

回答

10
  1. ExecutorService

    ExecutorService executor=Executors.newFixedThreadPool(50);

    它是簡單和易於使用。它隱藏了ThreadPoolExecutor的低層次細節。

    當數量爲Callable/Runnable任務數量較少並且在無界隊列中堆疊任務不會增加內存時,首選此項&降低系統性能。如果您有CPU/Memory約束條件,請使用ThreadPoolExecutor和容量約束& RejectedExecutionHandler來處理拒絕任務。

  2. CountDownLatch

    你已經初始化CountDownLatch與給定數。該計數通過調用countDown()方法遞減。我假設你稍後在你的Runnable任務中調用遞減。等待此計數達到零的線程可以調用await()方法之一。調用await()會阻塞該線程,直到計數達到零。 該類使Java線程能夠等待其他線程完成其任務。

    使用案例:

    1. 實現最大並行:有時候,我們希望在同一時間啓動多個線程來實現最大並行

    2. 等待N個線程開始之前完成執行

    3. 死鎖檢測。

      有更多的細節來看看這款article通過LOKESH古普塔。

  3. ThreadPoolExecutor:它提供了更多的控制,以微調各個線程池參數。如果您的應用程序受到活動Runnable/Callable任務數量的限制,則應通過設置最大容量來使用有界隊列。一旦隊列達到最大容量,您可以定義RejectionHandler。 Java提供了四種類型的RejectedExecutionHandlerpolicies

    1. 在默認ThreadPoolExecutor.AbortPolicy,處理程序拋出時甩運行時RejectedExecutionException。

    2. ThreadPoolExecutor.CallerRunsPolicy中,調用自身執行的線程運行該任務。這提供了一個簡單的反饋控制機制,可以減慢提交新任務的速度。

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

    4. ThreadPoolExecutor.DiscardOldestPolicy,如果執行程序沒有關閉,在工作隊列頭部的任務將被丟棄,然後執行重試(可再次失敗,導致此重複。)

      如果要模擬CountDownLatch行爲,則可以使用invokeAll()方法。你沒有報價

  4. 還有一個機制是ForkJoinPool

    ForkJoinPool加入到Java在Java中7 ForkJoinPool類似於 了Java ExecutorService但有一個區別。 ForkJoinPool使它 易於任務將其工作分成更小的任務,然後 提交到ForkJoinPool太。任務竊取發生在ForkJoinPool時,空閒工作線程從繁忙工作線程隊列中竊取任務。

    Java 8已經在ExecutorService中引入了更多API來創建工作搶佔池。您不必創建RecursiveTaskRecursiveAction但仍然可以使用ForkJoinPool

    public static ExecutorService newWorkStealingPool() 
    

    創建使用所有可用的處理器作爲其目標並行水平工作竊取線程池。

    默認情況下,它會佔用CPU內核的參數的數量。

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