2012-07-18 49 views
2

我想啓動大量任務以在+ -42Mio記錄的數據庫上運行。我想分批運行5000個記錄/時間(結果爲850個任務)。 我也想限制線(16)的Java的數量開始爲我做到這一點,我使用的是當前的代碼來完成這個任務:多線程最佳實踐:約束任務newFixedThreadPool

ExecutorService executorService = Executors.newFixedThreadPool(16); 
for (int j = 1; j < 900 + 1; j++) { 
    int start = (j - 1) * 5000; 
    int stop = (j) * 5000- 1; 
    FetcherRunner runner = new FetcherRunner(routes, start, stop); 
    executorService.submit(runner); 

    Thread t = new Thread(runner); 
    threadsList.add(t); 
    t.start(); 
} 

這是這樣做的正確方法?特別是我印象中的Java剛剛激發了所有任務...(FetcherRunner器具runnable

回答

3

使用ExecutorService的第一部分看起來很不錯:

... 
FetcherRunner runner = new FetcherRunner(routes, start, stop); 
executorService.submit(runner); 

與螺紋部分不應該在那裏,我我假設你在那裏只是爲了展示你以前是如何做到的?

更新: 是的,你不需要的代碼executorService.submit(runner)之後,也就是要結束了產卵的線程數量巨大。如果你的目標是要等待所有提交的任務的循環後完成,那麼你就可以在提交任務時得到Future參考,並等待在Future,像這樣:

ExecutorService executorService = Executors.newFixedThreadPool(16); 
List<Future<Result>> futures = ..; 
for (int j = 1; j < 900+ 1; j++) { 
int start = (j - 1) * 5000; 
int stop = (j) * 5000- 1; 
FetcherRunner runner = new FetcherRunner(routes, start, stop); 
futures.add(executorService.submit(runner)); 

} 
for (Future<Result> future:futures){ 
    future.get(); //Do something with the results.. 
} 
+0

我確實有......但是我用的是對答時完成我所有的線程,所以我可以繼續處理結果來檢測。你是否建議我應該放棄.submit之後的所有內容? +會不會有問題的,如果我限制maxThreads至10時,我trowing在執行任務900。 – FireFox 2012-07-18 01:46:26

+0

@all,謝謝你的提示,我不知道我是複製線程! @ Biju,yuo是最清楚解釋發生了什麼:) – FireFox 2012-07-18 02:12:57

3

這是正確的工作方式?

第一部分是正確的。但是你不應該創建和啓動新的Thread對象。當您提交Runnable時,ExecutorService將其放在隊列中,然後在工作線程變爲可用時運行它。

....我使用線程列表來檢測我的所有線程何時完成,以便我可以繼續處理結果。

那麼,如果你做你現在正在做的事情,你正在運行每個任務兩次。更糟糕的是,手動創建的線程羣將全部嘗試並行運行。

確保所有任務都已完成的簡單方法是在ExecutorService上調用awaitTermination(...)。 (執行者服務的一個有序的關閉將有同樣的效果......如果你不打算再次使用它。)

另一種方法是創建一個Future每個FetcherRunner的結果,並嘗試get所有任務提交後的結果。這樣做的好處是,您可以在生成後續結果之前開始處理早期結果。 (不過,如果你不需要......或者不能......做到這一點,利用期貨起不到任何東西。)

0

從您的代碼更改:

ExecutorService executorService = Executors.newFixedThreadPool(16); 
    for (int j = 1; j < 900 + 1; j++) { 
     int start = (j - 1) * 5000; 
     int stop = (j) * 5000 - 1; 
     FetcherRunner runner = new FetcherRunner(routes, start, stop); 
     executorService.submit(runner); 

    } 
2

你不在提交電話之後,不需要該部分。您創建線程的代碼將導致創建900個線程! Yowza。 ExecutorService具有16個線程池,您可以一次運行16個作業。所有16個線程忙時提交的任何作業都將排隊。從文檔:

Creates a thread pool that reuses a fixed number of threads operating off a shared 
unbounded queue. At any point, at most nThreads threads will be active processing tasks. 
If additional tasks are submitted when all threads are active, they will wait in the 
queue until a thread is available. If any thread terminates due to a failure during 
execution prior to shutdown, a new one will take its place if needed to execute 
subsequent tasks. The threads in the pool will exist until it is explicitly shutdown. 

因此,不需要另一個線程。如果您需要在任務完成後收到通知,您可以發出通知。其他選項是緩存所有的未來的從提交返回,並且一旦完成每一項任務,你可以檢查,看看是否所有的Future的完成。畢竟Future完成後,你可以派遣另一個函數來運行。但它會在ExecutorService中的其中一個線程上運行。

0

,最好的辦法是使用countdownlatch作爲下finally塊使用latch.countDown();代碼後await()只會當所有任務完成執行在FetcherRunner如下

ExecutorService executorService = Executors.newFixedThreadPool(16); 
    CountdownLatch latch = new CountdownLatch(900); 
FetcherRunner runner = new FetcherRunner(routes, start, stop, latch); 
latch.await();