2011-09-01 140 views
4

我有一個ThreadPoolExecutor,當我調用getActiveCount()時,它似乎對我撒謊。然而,我沒有做很多多線程編程,所以也許我做了一些不正確的事情。ThreadPoolExecutor的getActiveCount()

這裏是我的TPE

@Override 
public void afterPropertiesSet() throws Exception { 

    BlockingQueue<Runnable> workQueue; 
    int maxQueueLength = threadPoolConfiguration.getMaximumQueueLength(); 
    if (maxQueueLength == 0) { 
     workQueue = new LinkedBlockingQueue<Runnable>(); 
    } else { 
     workQueue = new LinkedBlockingQueue<Runnable>(maxQueueLength); 
    } 

    pool = new ThreadPoolExecutor(
        threadPoolConfiguration.getCorePoolSize(), 
        threadPoolConfiguration.getMaximumPoolSize(), 
        threadPoolConfiguration.getKeepAliveTime(), 
        TimeUnit.valueOf(threadPoolConfiguration.getTimeUnit()), 
        workQueue, 
        // Default thread factory creates normal-priority, 
        // non-daemon threads. 
        Executors.defaultThreadFactory(), 
        // Run any rejected task directly in the calling thread. 
        // In this way no records will be lost due to rejection 
        // however, no records will be added to the workQueue 
        // while the calling thread is processing a Task, so set 
        // your queue-size appropriately. 
        // 
        // This also means MaxThreadCount+1 tasks may run 
        // concurrently. If you REALLY want a max of MaxThreadCount 
        // threads don't use this. 
        new ThreadPoolExecutor.CallerRunsPolicy()); 
} 

在這個類中我也有,我進入我的Runnable(FooWorker)一個DAO,像這樣:

@Override 
public void addTask(FooRecord record) { 
    if (pool == null) { 
     throw new FooException(ERROR_THREAD_POOL_CONFIGURATION_NOT_SET); 
    } 
    pool.execute(new FooWorker(context, calculator, dao, record)); 
} 

FooWorker運行record(唯一的非單身人士)通過calculator通過狀態機然後通過dao發送轉換到數據庫,如下所示:

public void run() { 
    calculator.calculate(record); 
    dao.save(record); 
} 

一旦我的主線程完成創建新的任務我嘗試和等待,以確保所有線程成功完成:

while (pool.getActiveCount() > 0) { 
    recordHandler.awaitTermination(terminationTimeout, 
            terminationTimeoutUnit); 
} 

我從輸出日誌中看到什麼(這大概是不可靠的,由於線程) getActiveCount()過早返回零,並且while()循環正在退出,而我的最後一個線程仍在打印calculator的輸出。

注意我也嘗試過撥打pool.shutdown(),然後使用awaitTermination,但接下來我的作業運行池仍然關閉。

我唯一猜測是一個線程裏面,當我發送數據到dao(因爲它是由Spring在主線程中......創造了一個單),JAVA是考慮到線程激活,因爲(我承擔)正在處理/等待主線程。

直覺上,僅基於我所看到的,這是我的猜測。但是......這是真的嗎?如果沒有在run()的頂部添加手動增量變量並在最後遞減以跟蹤線程數量,有沒有辦法「做到這一點」?

如果答案是「不要通過dao」,那麼我不必爲每個線程「新增」一個DAO嗎?我的過程已經是一個(美麗,高效)的野獸,但這真的很糟糕。

回答

7

由於the JavaDoc of getActiveCount states,這是一個近似值:你不應該基於任何主要的業務邏輯決策。

如果你想等待所有安排的任務來完成,那麼你只需要使用

pool.shutdown(); 
pool.awaitTermination(terminationTimeout, terminationTimeoutUnit); 

如果你需要等待特定任務來完成,你應該使用submit()代替​​,然後檢查Future對象是否完成(如果要非阻塞地使用isDone()或通過簡單地調用get()阻止任務完成)。

+0

你知道我讀了多少次javadoc並完全忽略了「近似」?有趣的事。我想知道它爲什麼不準確......如果它不可靠,似乎毫無用處。 – inanutshellus

+1

@ Gabriel:它的「近似」原因可能是因爲獲得準確的計數*可能是一項昂貴的操作。 –

5

documentation表明,在ThreadPoolExecutor方法getActiveCount()不是一個確切的數字:

getActiveCount

公衆詮釋getActiveCount()

返回正在積極執行任務的線程的大致數量。

返回:線程

個人而言,當我做的多線程工作,像這樣的數字,我使用一個變量,我增加我添加任務,減量爲我搶他們的輸出。