一個簡單的ThreadPool
? 原文來自
http://www.informit.com/articles/printerfriendly.asp?p=30483&r1=1&rl=1? 項目是多線程的,所以引入了線程池這個東西。池子是個老美寫的。在項目中表現的還不錯。所以把它摘出來,介紹給以后或許需要用到它的同行們。
? 關于為什么要采用ThreadPool,原文已經提到了:創建一個線程是需要開銷的;如果線程數量過大的話,cpu就會浪費很大的精力做線程切換。
? ThreadPool的實現過程就是對WorkerThread的同步和通信的管理過程。
? 我們來看代碼。
? 首先,在ThreadPool構造的時候,創建10個WorkerThread(size=10)并讓他們運行。每個WorkerThread線程都有個ThreadPool的引用,用于查詢ThreadPool的狀態和獲得同步鎖.WorkerThread運行以后,循環調用ThreadPool的方法進行查詢,如果沒有發現任務,ThreadPool告訴正在查詢的線程進入休眠狀態,WorkerThread釋放對查詢方法的鎖定.這樣在還沒有任務的時候,所有的10個WorkerThread都會進入休眠狀態,進入等待ThreadPool對象的等待鎖定池,只有ThreadPool對象發出notify方法(或notifyAll)后WorkerThread線程才進入對象鎖定池準備獲得對象鎖進入運行狀態。
代碼片斷:
while ( !assignments.iterator().hasNext() )
??? wait();
如果你有jprofile或者其他的觀察線程的工具,你可以看到有10個線程都在休眠狀態.
? 接著,我們向ThreadPool中加入任務,這些任務都實現了Runnable的run方法.(至于為什么把任務都做成Runnable,譯者至今也有些疑問?預定俗成?TimerTask也是實現自Runnable,弄得初學者經常把真正運行的線程搞混).ThreadPool每assign一個任務,就會發出一條消息,通知它的等待鎖定池中的線程.各個線程以搶占的方式獲得對象鎖,然后很順利的獲得一條任務.并把此任務從ThreadPool里面刪除.沒有搶到的繼續等待.
Runnable r = (Runnable)assignments.iterator().next();
?? assignments.remove(r);
WorkerThread從ThreadPool那里獲得了任務,繼續向下執行。
target = owner.getAssignment();
?? if (target!=null) {
??? target.run();?????
??? owner.done.workerEnd();
?? }
記住,這里調用的是target.run();而不是調用的線程的start()方法。也就是說在這里表現出的WorkerThread和task之間的關系僅僅是簡單的方法調用的關系,并沒有額外產生新線程。(這就是我上面納悶為什么大家都實現Runnable來做task的原因)
?大家可能注意到,WorkerThread并沒有對異常作處理。而我們知道發生在線程上的異常會導致線程死亡。解決的辦法有2中,一種是通過threadpool的管理來重新激起一個線程,一種是把異常在線程之內消滅。在項目中,我采用的是第二中,因此這個片斷改稱這樣:
if (target!=null) {
? try{
??? target.run();?????
?? }
? catch(Throwable t){
?.......
?? }
??? owner.done.workerEnd();
}
在WorkerThread完成一個task以后,繼續循環作同樣的流程.
在這個ThreadPool的實現里面,Jeff Heaton用了一個Done類來觀察WorkerThread的執行情況.和ThreadPoool的等待鎖定池不同,Done的等待鎖定池里面放的是初始化ThreadPool的線程(可能是你的主線程),我們叫他母線程.
? 在給出的測試例子中.母線程在調用complete()方法后進入休眠(在監視中等待),一開始是waitBegin()讓他休眠,在assign加入task以后,waitDone()方法讓他休眠.在WorkerThread完成一個task以后,通知waitDone()起來重新檢查activeThreads的數值.若不為0,繼續睡覺.若為0,那么母線程走完,死亡(這個時候該做的task已經做完了).母線程走完,ThreadPool還存在嗎?答案是存在,因為WorkerThread還沒有消亡,他們在等待下一批任務,他們有ThreadPool的引用,保證ThreadPool依然存在.大家或許已經明白Done這個類的作用了.
? 細心的讀者或許會發現,發生在Done實例上的notify()并不是像ThreadPool上的notify()那樣每次都能完成一項工作.比如除了第一個被assign的task,其他的task在assign進去的時候,發出的notify()對于waitDone()來說是句"狼來了".
?最后在ThreadPool需要被清理得時候,使每一個WorkerThread中斷(這個時候或許所有的WorkerThread都在休眠)并銷毀.記住這里也是一個異步的過程.等到每一個WorkerThread都已經銷毀,finalize()的方法體走完.ThreadPool被銷毀.
?for (int i=0;i<threads.length;i++) {
?? threads[i].interrupt();
?? done.workerBegin();
?? threads[i].destroy();
? }
? done.waitDone();
為什么有句done.workerBegin();?不明白.
參考文章:
http://www.zdnet.com.cn/developer/common/printfriend/printfriendly.htm?AT=39276905-3800066897t-20000560c