2

我正在使用具有不同運行時間的任務的多線程應用程序。當一個線程完成時,是否有辦法從一個仍在運行的線程中接管一些任務?Java:如何將完成的線程從正在運行的線程提取任務

這裏是一個例子。我用5個線程啓動了我的程序,每個程序都有50個任務。當最快的運行線程完成時,另一個線程仍然有40個任務要完成。我怎樣才能讓完成的線程從另一個線程執行20個任務,因此每個線程都繼續工作20個,而不是等待正在運行的線程完成剩下的40個任務?

+1

查看[Executor](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html) – jhamon

+3

您正在描述「盜取工作」。 [用於'ForkJoinPool'的Javadoc](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ForkJoinPool.html)明確指出它「與其他類型的ExecutorService主要不同僱用工作偷竊的美德「。 –

+0

@AndyTurner不是真的,他只是想把任務分配給一個可用的線程 –

回答

3

使用ForkJoinPool

一個ForkJoinPool與其他類型的ExecutorService的不同之處主要憑藉用人偷盜的:所有的線程池中試圖找到並執行其他活動任務創建子任務(最終阻塞等待如果沒有任何工作)。當大多數任務產生其他子任務時(如大多數ForkJoinTasks),這可以實現高效處理。在構造函數中將asyncMode設置爲true時,ForkJoinPools可能也適合用於永不連接的事件樣式任務。

的Java 8提供了執行人

static ExecutorService newWorkStealingPool() 

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

ForkJoinPool task stealing

看一看這個igvtia article通過Ilya Grigorik更多的細節。

看一看其它相關的Java併發API @tutorialsThreadPoolExecutorExecutorService

+0

謝謝拉文德拉。每個人的輸入都有幫助,但ForkJoinPool似乎是我正在尋找的東西(我們已經在使用線程池)。在你鏈接的文章中解釋的想法是我想到的,所以我會給ForkJoinPool一個嘗試。 –

+0

如果您需要偷工減料的行爲,但對真正的fork/join遞歸任務分解不感興趣,請考慮使用['Executors.newWorkStealingPool'](http://docs.oracle.com/javase/8/docs/api改爲/java/util/concurrent/Executors.html#newWorkStealingPool--)。雖然這個方法目前確實返回了一個'ForkJoinPool'實例,它將來可能會返回一個更高效的工作線程池實現。 – glts

3

使用線程池,其中創建感謝Executors類:

ExecutorService es = Executors.newFixedThreadPool(5); 
List<Runnable> tasks = // create your 50 runnable 
List<Future<?>> futures = new ArrayList<>(tasks.size()); 
for(Runnable r : tasks) { 
    Future<?> f = es.submit(t); 
    futures.add(f); 
} 

的文檔解釋了相當不錯它是如何工作的,所以我建議你給它看看。

0

不要讓線程承擔多個任務。這樣,任何完成其任務的線程都會採用隊列中的下一個可用任務。這些線程並不是爲每個任務創建的,而是正在被重用,所以幾乎沒有開銷。

考慮 - 2個線程每個都有20個任務,並且如果第二個線程尚未完成,您希望第二個線程從第一個線程接管任務。將此比較爲由2個線程服務的隊列中的40個任務,這意味着任務總是儘可能快地執行,而不需要在線程間移動它們的複雜性。

我沒有看到問題中的邏輯 - 如果由於排序問題而導致無法進行多線程的任務組(這是我看到提交本身是一組任務的唯一原因任務放到隊列中),那麼你不能讓另一個線程接管未完成的處理(因爲那麼整個組的排序將被破壞)。如果您不需要排序處理,那麼將所有任務放到隊列中並儘快執行。

如果您總是希望來自給定組的任務能夠更快執行,請爲其分配更高的優先級並使用由多個線程提供服務的優先級隊列。

相關問題