2009-11-05 148 views
25

我有這個相當簡單的問題關於ThreadPoolExecutor。我有以下情況:我必須從隊列中消耗對象,爲它們創建適當的輔助任務並將它們提交給ThreadPoolExecutor。這很簡單。但在關機場景中,許多工人可能會排隊執行。由於其中一個任務可能會運行一個小時,並且我希望能夠相對快速地正常關閉應用程序,所以我希望在正常完成已處理任務的同時放棄ThreadPoolExecutor中的所有排隊任務。刪除ThreadPoolExecutor的所有排隊任務

ThreadPoolExecutor文檔有一個remove()方法,但只允許刪除特定的任務。 purge()僅適用於已取消的未來任務。我的想法是清除隊列中所有排隊的任務。該的ThreadPoolExecutor提供訪問該內部隊列但文檔指出:

方法getQueue()允許訪問 工作隊列監測 和調試的目的。對於任何其他目的,使用此方法 強烈建議 不鼓勵。

所以抓住這個隊列並清除它不是一個選項。此外,該片斷的文件說:

兩個提供的方法, 刪除(一個java.lang.Runnable)和清除() 可存儲協助 填海當大量的 排隊的任務變得取消。

怎麼樣?當然,我可以維護我提交給執行者的所有任務的列表,並且在關閉的情況下,我遍歷所有條目並使用remove()方法將它們從ThreadPoolExecutor中移除...但是...來吧,這是一個浪費內存和維護這份清單的麻煩。 (刪除已執行的任務,例如)

我欣賞任何提示或解決方案!

回答

9

您是否考慮包裝ExecutorService?創建一個

CleanShutdownExecutorService implements Executor 

將所有調用委託給另一個執行器,但將期貨保留在它自己的列表中。 CleanShutdownExecutorService然後可以有一個cancelRemainingTasks()方法調用shutdown(),然後在其列表中的所有Futures上調用cancel(false)。

+0

這可能是最乾淨的方法,因此我接受這個答案。 :-)即使我希望已經有這樣的東西......所以:讓我們編寫這個東西。 :-) – Malax 2009-11-06 09:22:23

4

由於ExecutorService.shutdown()做得不夠,並ExecutorService.shutdownNow()做太多我想你必須寫一些東西在中間:記得你所有提交的任務和(或之前)調用shutdown()後手動刪除它們。

+0

」啓動有序關閉,其中執行先前提交的任務,但不會接受新任務。「我提交了幾個不應該執行的任務。但**正在執行的任務不應該結束。 – Malax 2009-11-05 10:21:51

+0

您編輯了您的答案,因此我的評論不再完全有效。不過,shutdownNow()文檔指出:「試圖停止所有正在執行的任務。」這不是我想要的。 :) – Malax 2009-11-05 10:25:30

+0

哦,對了,我重讀了這句話的一半。那麼,我想你唯一的選擇就是記住所有提交的'Runnable'並手動刪除它們。我會相應地編輯。 – Bombe 2009-11-05 11:11:09

1

Bombe的答案正是你想要的。 shutdownNow()停止一切使用核子和鋪路的方法。這是你可以做的最好的事情,而不是繼承你正在使用的ThreadPoolExecutor的實現。

0

一個瘋狂的和不潔的解決方案,它可能工作(不是真正的思想通過或測試)將覆蓋您WorkerTasks只有在情況下,一些全球價值設定的interrupt()拒絕關機時interrupt()由shutdownNow時(要求他們)。

那應該讓你用shutdownNow()不行?

0

告訴你的線程池關閉getQueue,每個結果放入單獨的Runnables,使用remove方法刪除每個Runnable。根據隊列的類型,您可能能夠基於返回值提前中止刪除。

基本上,這是抓住隊列並清除它,只通過工作的方法清除。您不必手動記住所有提交內容,而是使用線程池必須記住所有提交內容的事實。但是,您可能需要製作隊列的防禦副本,因爲我認爲這是一個實時視圖,因此如果您正在對實時視圖進行迭代/ for-eaching,則刪除可能會導致併發修改異常。

12

我曾經在長時間運行線程的應用程序上工作。我們在關機時這樣做,

BlockingQueue<Runnable> queue = threadPool.getQueue(); 
List<Runnable> list = new ArrayList<Runnable>(); 
int tasks = queue.drainTo(list); 

列表被保存到文件。在啓動時,該列表被添加回池中,所以我們不會丟失任何工作。

+2

好的除了我的問題。 :-)我的情況下任務的持久性不是問題。但是你的補充可能會幫助其他人,謝謝! :) – Malax 2009-11-06 09:17:27

+0

我不確定這是否是正確的方法。如果通過shutdown()方法關閉,它將一直等到所有內容都被終止(甚至是排隊的任務),如果使用shutdownNow()方法執行該操作,則該方法已經返回排除的排隊任務列表。僅供參考。 – Whimusical 2015-12-09 23:44:04

0

不是awaitTermination(long timeout, TimeUnit unit)關機後工作嗎?

executor.shutdown(); executor.awaitTermination(60 TimeUnit.SECONDS)

1

您可以嘗試allowCoreThreadTimeOut(true);

+0

你應該開發你的答案,並明確表明你實際上是_answering_ OP。 – 2012-12-08 21:20:11

3

這是一個老問題,但在這種情況下幫助別人:你可以設置一個揮發性布爾當你調用shutdown()並且如果在真正開始之前設置布爾值,則每個提交的任務都會終止。這將允許真正開始完成的任務,但會阻止排隊的任務開始其實際活動。 「

相關問題