線程池是管理線程的進階技術,通常它提供了如下功能:
- 通過對線程的管理,更加合理的調配資源。通常,線程池裡維護著一組空閑線程,並向外提供,根據系統繁忙程度動態增加或減少空閑線程的數量。比較進階的還提供了自動檢測異常線程的功能。
- 通過維護池中既存線程,可以節省建立線程的開銷,尤其是對於web server這類處理頻繁,而處理過程又比較快的程式,建立線程的開銷是不能忽略的。
類似在裸機上加OS能夠合理管理電腦資源,使用線程池能夠低開銷且有效管理線程的生命週期和系統資源,同時提供更為方便易用的介面對外,使得開發更加快速安全。
對於簡單的線程池,可以參考文章《Java 理論與實踐: 線程池與工作隊列》
,這裡實現了一個簡單的帶工作隊列(Queue)的線程池,當然,也有一些簡單的調度,這裡就不再贅述。
線程池架構
相對於jdk1.5中的ThreadPoolExecutor中複雜的調度和規劃,上面的例子還稍微簡單了些。Doug Lee定義了命令模式的介面Executor,使得線程的執行邏輯和時序邏輯得到了分離,提高了健壯性和可擴張性,使得需求變化時不再是將整個程式重寫而只需修改相應的執行邏輯----至於時序邏輯,交給ThreadPool吧,它會幫你搞定一切的。不相信?那不如讓我們inside ThreadPoolExecutor去看看它是怎麼實現這項神奇的功能。
首先我們對ThreadPoolExecutor的架構來一個總體的認識,ThreadPoolExecutor繼承了AbstractExecutorService,後者實現了ExecutorService介面,同時ExecutorService又是Executor的子介面;也就是說ThreadPoolExecutor其實是一個Executor的實現。示。
ThreadPoolExecutor內部共有5個類,其中 RejectExecutionHandler定義了對任務的丟棄方式,它之下有4個執行個體類。Worker類其實就是線上程池中執行的線程實體,所以它也很重要,可以注意到它被定義為一個內部類,從而可以方便的訪問ThreadPoolExecutor類的方法。
這裡簡單的先介紹一下這些與ThreadPoolExecutor有關的介面或類。Executor已經介紹過了,就是讓邏輯分離而做的介面,它定義了抽象方法execute()。而ExecutorService則是負責管理一組任務的服務介面,它的一些實現都已經在其子類AbstractExecutorService中完成了。ThreadPoolExecutor需要實現execute()和shutdown()等抽象方法。
ThreadPoolExecutor程式碼分析
execute()是整個線程池最核心的方法,可以說線程池對任務的調度就是在這裡實現的。來看for迴圈,如果當前線程池正在運行,則用reject策略將任務reject掉;如果當前線程數小於核心池數量,就new新線程來解決當前任務,注意即使是活動線程空閑也不會使用它們;一旦線程數超過核心池數量,則不再new新線程,而是向隊列中新增工作,這裡也分成功失敗(隊列滿則失敗),成功說明當前線程數滿足當前任務數;失敗就表示核心池數量的線程已經不能滿足當前任務數了,這時就會啟用後備線程;addIfUnderMaximumPoolSize(command)返回的結果其實有三種情況:1.建立線程處理當前任務;2.未建立成功;3.建立線程處理了隊列裡的任務,但未處理當前任務,前兩種情況都在後面用if進行了判斷,只有最後的情況是需要 for迴圈重新處理的。
public void execute(Runnable command) { if (command == null) throw new NullPointerException(); for (;;) { if (runState != RUNNING) { reject(command); return; } if (poolSize < corePoolSize && addIfUnderCorePoolSize(command)) return; if (workQueue.offer(command)) return; Runnable r = addIfUnderMaximumPoolSize(command); if (r == command) return; if (r == null) { reject(command); return; } // else retry } } |
更多,請參閱http://www.360watcher.net/html/35/656.htm