本文是對java線程池的粗淺分析,視野局限于線程池的基本實現,不包含生命周期,狀態管理。
線程池的特點是將任務的提交和執行分開。這樣做的好處是,能使處理器盡量多地同時執行任務。
為此,線程池提供了兩個角色:
任務 task
執行任務的工人 worker
與此相關,需要考慮:
工人的數量:
工人數量的考量是線程池設計的一個關鍵。因此,這一點由構造線程池時,提供的頭兩個參數決定。
最小雇傭數量 corePoolSize
最多工人數量 maximumPoolSize
何時解雇多余最小雇傭數量的工人:
工人多余任務時,它們會等待任務的到來,如果規定時間內,還沒有任務,那我們就解雇多余的工人。
這個規定的時間就是構造子里的第三,第四個參數。
能接受的任務數量:
一個工人,某一時間只能處理一個任務。工人的數量是有限的,因此多余工人數量的任務來了時:
線程池就要考慮是否接受
Y:
處于等待中的任務堆積到多少就不再允許接受任務 :
規定等待任務列表的容量[bound],達到容量后不再接受新任務。
無限制地接受等待任務[unbound]
設置何種任務等待列表由構造子的第五個參數決定。
long keepAliveTime, TimeUnit unit
N:
以何種方式拒絕:
由構造子的第七個參數決定。
第六個參數決定了
工人手里執行任務線程的工廠方法。
工作原理:
1.當工人數量沒有達到最小雇傭數量時,每當任務來臨,線程池都要創建一個工人,然后從線程工廠里創建一個新的線程,把任務作為該線程的target,把線程交給工人,把工人加入工人集合。該任務隨即被執行。
2.如果任務來臨時,當前工人數量poolSize已經大于最小雇傭數量,表明工人已經雇傭的差不多了,先讓任務等待吧。
線程池嘗試把任務加入任務列表,如果成功,任務提交的步驟就結束了。
2.5.任務列表是并發阻塞隊列,工人會不斷地嘗試從隊列里獲取任務,如果獲取到任務(請看5),工人就把任務拿去執行。這是任務的執行步驟。
3.如果加入隊列失敗,說明任務列表已經滿了,不能再往里塞任務了。
這時,線程池判斷工人數量是否達到最多工人數量。
如果還沒有,則決定再雇傭一個工人(這和開始雇傭工人的步驟沒有兩樣)。
4.如果已經達到雇傭上線,線程池沒有辦法了,只好拒絕該任務。
拒絕的方式有:
1、拋出異常給任務遞送者,告訴他“老子累屁了,老子真的不干了”。 --這太粗暴了。線程池默認就這么干!
2、偷蔫兒地丟棄這個任務。 --這太猥瑣了。
3、從任務列表里丟棄一個最近的任務,然后把這個任務放里。--這太勢利眼了。
4、還給任務遞送者,讓他自己干。--這太無恥了。
5.線程池讓工人等待任務的策略分兩種(本文不考慮生命周期和狀態):
死等!當工人數量少于或者等于最低雇傭數量時,它們沒啥任務干了,就必須死等。
如果在給定時間內,沒有任務來到,線程池開始數人頭,如果不多于最低雇傭數量,這個工人還得重新等一個給定時間那么長。
6.否則,線程池把該工人的線程結束,告訴當前等待的工人,你沒有任務了。不要再等了。
7.沒有拿到任務的工人,被清除出工人集合--該工人正式下崗。
feuyeux@gmail.com