2016-03-07 103 views
0

對於我的Java項目,我想並行執行兩個任務併合並它們的結果。問題是我必須在每次執行時調用多次(可能是1000次或更多)的方法中執行此操作。 我試着用的ExecutorService和線程池,但如果我宣佈的ExecutorService作爲一類領域,開始提交的工作吧,在某個時刻,它拋出一個Java - 重用線程池

java.lang.OutOfMemoryError: unable to create new native thread 

所以我決定去與此代碼:

ExecutorService executor = Executors.newFixedThreadPool(2); 

Future<Integer> taskOne = executor.submit(new Callable<Integer>() { 
    public Integer call() throws Exception { 
     //Do work... 
     return 0; 
    } 
}); 

Future<Integer> task2 = executor.submit(new Callable<Integer>() { 
    public Integer call() throws Exception { 
     //Do work... 
     return 0; 
    } 
}); 

task1.get(); 
task2.get(); 

executor.shutdown(); 

while(!executor.isTerminated()); 

問題是,與單線程解決方案相比,採用這種新方法後,應用程序性能更差。我認爲這是由於在每個方法調用上創建一個新的線程池的開銷。

所以,我的問題是:有沒有辦法做同樣的任務,但不必創建和關閉線程池每個方法的調用?

謝謝。

+1

在每次調用時創建一個線程池沒有意義。你能發佈原始代碼嗎? – shmosel

+0

'task1.get()'是一個阻塞操作,所以你已經有了兩個任務結果。沒有必要關閉執行程序並重新創建它。每次執行應用程序只執行一次。 – Cosu

回答

1

我不一定會說它本身就是一種劣質設計,但需要考慮一些事情。就我個人而言,我喜歡線程池,如果使用正確,它是一個強大的解決方案。

性能降低的原因是固定池大小爲2時,只能同時運行兩個線程。有可能你需要一個更大的數字 - 可能是10,可能是100 - 但至少你可以設計它,這樣你就不會耗盡內存。也就是說,如果原始設計因爲創建的線程太多而耗盡內存,那麼您肯定需要一次限制活動的線程數,因此您的性能將會受到一些打擊......它只是不會不需要全部或沒有。

您也可以使用無限執行程序線程池,假設正在運行的線程確實以及時返回的方式返回,以至於仍然不會最大化線程。如果線程以某種確定的方式返回,當線程返回到池時,它將立即可用於下一個可用的任務,而無需創建任何東西。所以這很好。

大家都說,看看異常消息,也可能在操作系統級別,無法創建更多的線程,無論您在Java中做了什麼。我有一個在CentOS上運行的服務,我合法地必須增加每個進程允許的線程數(在這種情況下,一個Java進程運行我的服務),因爲有一個最大值,我打它。如果你正在運行某種linux風格,那也可能是這樣,尤其是因爲看起來線程本身除了返回外什麼都不做。

+0

謝謝。最終的解決方案是將ExecutorService聲明爲靜態字段,因爲在我的代碼中,我創建了許多同一類的實例,並且每個實例都有不同的ExecutorService,消耗了不必要的操作系統線程 –

0

您所描述的class field解決方案聽起來像是一種更好的設計。游泳池的大小是多少?您應該調試OutOfMemoryError而不是切換到低級設計。