接上篇,在上篇中介紹了線程池的設計需求以及使用,在這裡我們分析 Concurrent包中線程池的實現類ThreadPoolExecutor的設計,是不是感覺沒意義 ,人家都實現了還分析啥?當然是提高我們自身的設計能力了。對於設計能力的 提高,我認為一方面我們要在具體實踐中,能夠學習前人
總結的設計思想(比如設計模式之類的),根據具體上下文,能夠融會貫通 的使用他們。另一方面分析優秀的框架設計與實現也是很好的方式,當然JDK設 計是最好的學習資料。閒話多了,切入主題,設計要點:
縱觀在JDK1.5以前我們自己實現的線程池,還是Concurrent提供的線程池, 在線程池中首先我們要兩個容器維護線程池中的線程與提交給線程池中的Task。
線程池與Task如何關聯,什麼樣的Task才可以提交的該線程池中執行呢。所 以我們要定義一個接口,分離線程池與具體
Task的耦合關系,ThreadPoolExecutor可以接受實現Runnable接口或者 Callable接口(其實最後也是組裝為Runnable接口)的具體Task。
線程池中的線程從Task隊列中去Task執行。
以上就是線程池設計的要點。
在ThreadPoolExecutor中,有一個內部類Worker,實現了Runnable,也就是 線程池中的線程,不言而喻,它的Run方法就是從Task隊列
取Task,調用Task的run方法(Task 是實現了Runnable接口的),執行Task ,依次類推,直到沒有隊列裡面Task。看下圖
了解了線程的創建以及執行Task的流程,下面讓我們在看看 ThreadPoolExecutor是如何觸發創建線程池線程的呢? 何時啟動線程池裡的
線程執行Task呢?再這之前,我們先說明一下,在ThreadPoolExecutor中引 入了兩個描述線程池中線程數量的屬性,corePoolSize和maximumPoolSize
corePoolSize 初始化時線程池中線程的數量。
maximumPoolSize 線程池中的程的最大數量,當Task無法插入Task隊列,線 程池線程數量又達到maximumPoolSize時,啟用Reject策略,
Reject過多的Task。
下圖說明了當我們創建一個線程池,並提交Task時,ThreadPoolExecutor首 先判斷是否達到corePoolSize,沒有就在創建一個線程,提高吞吐量。如果超過 那麼直接將該Task插入Task隊列。
如果插入失敗,說明Task隊列已滿,那麼嘗試是否達到maximumPoolSize,如 果沒有,那麼創建而外的線程處理改
Task,減低Task失敗率。
如果已經達到了maximumPoolSize,對不起,只能Reject了。
這其實是線程池設計處理Task的策略。大家可以細細體會,這個策略的優勢 。
到現在其實已經基本說明了ThreadPoolExecutor的設計了,其實設計思想是 不是跟以前我們自個設計線程池都一樣?只是在具體實現上更加完善,更加完美 !
對了大家如果感興趣可以看看ThreadPoolExecutor如何優雅的Shutdown,這 些設計實現細節,都可以在我們的實踐中應用。