2012-03-30 55 views
3

我遇到了這個併發問題,我一直在撓頭我的好幾天。等待所有任務(未知號碼)完成 - ThreadPoolExecutor

基本上,我希望我的ThreadPoolExecutor在關閉之前等待所有任務(任務數量未知)完成。

public class AutoShutdownThreadPoolExecutor extends ThreadPoolExecutor{ 
    private static final Logger logger = Logger.getLogger(AutoShutdownThreadPoolExecutor.class); 
    private int executing = 0; 
    private ReentrantLock lock = new ReentrantLock(); 
    private final Condition newTaskCondition = lock.newCondition(); 
    private final int WAIT_FOR_NEW_TASK = 120000; 

    public AutoShutdownThreadPoolExecutor(int coorPoolSize, int maxPoolSize, long keepAliveTime, 
     TimeUnit seconds, BlockingQueue<Runnable> queue) { 
     super(coorPoolSize, maxPoolSize, keepAliveTime, seconds, queue); 
    } 


    @Override 
    public void execute(Runnable command) { 
     lock.lock(); 
     executing++; 
     lock.unlock(); 
     super.execute(command); 
    } 


    @Override 
    protected void afterExecute(Runnable r, Throwable t) { 
     super.afterExecute(r, t); 
     try{ 
      lock.lock(); 
      int count = executing--; 
      if(count == 0) { 
       newTaskCondition.await(WAIT_FOR_NEW_TASK, TimeUnit.MILLISECONDS); 
       if(count == 0){ 
        this.shutdown(); 
        logger.info("Shutting down Executor..."); 
       } 
      } 
     } 
     catch (InterruptedException e) { 
      logger.error("Sleeping task interrupted", e); 
     } 
     finally{ 
      lock.unlock(); 
     } 
    } 
} 

的目的是,爲任務計數器任務檢查(執行),如果它等於0,它阻止了一段時間,後來釋放其鎖,以便其他任務可能要執行的機會,不要太早關閉執行者。

但是,它沒有發生。所有4個線程在執行程序進入等待狀態:

"pool-1-thread-4" prio=6 tid=0x034a1000 nid=0x2d0 waiting on condition [0x039cf000] 
"pool-1-thread-3" prio=6 tid=0x034d0400 nid=0x1328 waiting on condition [0x0397f000] 
"pool-1-thread-2" prio=6 tid=0x03493400 nid=0x15ec waiting on condition [0x0392f000] 
"pool-1-thread-1" prio=6 tid=0x034c3800 nid=0x1fe4 waiting on condition [0x038df000] 

如果我在運行的類把日誌語句(應該減緩線向下),這個問題似乎消失了。

public void run() { 
    // logger.info("Starting task" + taskName); 
     try { 
      //doTask(); 
     } 
     catch (Exception e){ 
      logger.error("task " + taskName + " failed", e); 
     } 
} 

的問題是,類似這樣的帖子 Java ExecutorService: awaitTermination of all recursively created tasks

,我都按照原來的海報解決方案,試圖解決afterExecute()的比賽條件,但它不工作。

請幫忙解釋一下。 謝謝。

+0

使用CountDownLatch怎麼樣? – 2012-03-30 03:10:57

+0

任務數量事先未知。該程序將掃描其子文件夾中所有文件的目錄,並在每個文件上執行一些編號處理任務。 – TommyQ 2012-03-30 03:15:03

回答

1

你有你的任務等待這newTaskCondition,但沒有任何信號表明這種情況。所以你的線程都堆積如山,等待newTaskCondition,直到它超時。此外,阻止afterExecute將延遲完成任務,因此可能不是您想要做的事情。

如果您想讓它稍等一會兒以查看是否有更多工作進入,則此功能已存在。只需調用setKeepAliveTime來設置等待的時間,並設置allowCoreThreadTimeOut以確保所有線程(包括核心線程)都可以終止。

+0

這就是意圖。檢查是否沒有更多的任務 - >等待並釋放鎖定一段時間,(如果有新任務,他們應該拿起這個鎖) - >喚醒並重新獲得鎖 - >再次檢查,如果數量任務仍然是0 - >如果是,則關閉執行程序,如果不是,則退出任務。在這種情況下,沒有必要指示線程喚醒,我猜? – TommyQ 2012-03-30 03:24:29

+0

@TommyQ,這就是發生了什麼 - 一個任務運行,它看到沒有更多的線程,它開始等待120秒。重複四次,現在你有四個等待任務。除非定時器到期,否則什麼都不會喚醒它們,如果因爲忙於等待120秒而耗盡線程,那太糟糕了。內置Keepalive計時器有什麼問題? – bdonlan 2012-03-30 03:30:50

+0

setKeepAliveTime只適用於多餘的線程?我設置了corePoolsize = maxPoolsize; – TommyQ 2012-03-30 03:41:32

0

我發現了一個非常簡單的解決方案來解決我的問題。

儘管預先未知任務的數量,並且打算讓主線程等待threadPool中的所有任務完成,但已知所有任務的提交時間(在查找並提交後-task方法已經掃描了所有文件)。

我可以簡單地調用ThreadPoolExecutor.shutdown()和awaitTermination(Long.MAX_VALUE),以便主線程將無限期地等待ThreadPool完成其任務。