深入源碼分析Java線程池的實現(xiàn)原理

程序的運行,其本質上,是對系統(tǒng)資源(CPU、內存、磁盤、網(wǎng)絡等等)的使用。如何高效的使用這些資源是我們編程優(yōu)化演進的一個方向。今天說的線程池就是一種對CPU利用的優(yōu)化手段。

網(wǎng)上有不少介紹如何使用線程池的文章,那我想說點什么呢?我希望通過學習線程池原理,明白所有池化技術的基本設計思路。遇到其他相似問題可以解決。

池化技術

前面提到一個名詞——池化技術,那么到底什么是池化技術呢?

池化技術簡單點來說,就是提前保存大量的資源,以備不時之需。在機器資源有限的情況下,使用池化技術可以大大的提高資源的利用率,提升性能等。

在編程領域,比較典型的池化技術有:

線程池、連接池、內存池、對象池等。

本文主要來介紹一下其中比較簡單的線程池的實現(xiàn)原理,希望讀者們可以舉一反三,通過對線程池的理解,學習并掌握所有編程中池化技術的底層原理。

創(chuàng)建一個線程

在Java的并發(fā)編程中,線程是十分重要的,在Java中,創(chuàng)建一個線程比較簡單:

publicclassApp{

publicstaticvoidmain(String[]?args)throwsException{

newThread(newRunnable()?{

@Override

publicvoidrun(){

System.out.println("線程運行中");

}

}).start();

}

}

我們通過創(chuàng)建一個線程對象,并且實現(xiàn)Runnable接口就可以實現(xiàn)一個簡單的線程。可以利用上多核CPU。當一個任務結束,當前線程就接收。

但很多時候,我們不止會執(zhí)行一個任務。如果每次都是如此的創(chuàng)建線程->執(zhí)行任務->銷毀線程,會造成很大的性能開銷。

那能否一個線程創(chuàng)建后,執(zhí)行完一個任務后,又去執(zhí)行另一個任務,而不是銷毀。這就是線程池。

這也就是池化技術的思想,通過預先創(chuàng)建好多個線程,放在池中,這樣可以在需要使用線程的時候直接獲取,避免多次重復創(chuàng)建、銷毀帶來的開銷。

線程池的簡單使用

以下代碼,是在Java中創(chuàng)建線程池:

importjava.util.concurrent.*;

publicclassApp{

publicstaticvoidmain(String[]?args)throwsException{

ExecutorService?executorService?=newThreadPoolExecutor(1,1,

60L,?TimeUnit.SECONDS,

newArrayBlockingQueue<>(10));

executorService.execute(newRunnable()?{

@Override

publicvoidrun(){

System.out.println("abcdefg");

}

});

executorService.shutdown();

}

}

Jdk提供給外部的接口也很簡單。直接調用ThreadPoolExecutor構造一個就可以了,也可以通過Executors靜態(tài)工廠構建,但一般不建議。

可以看到,開發(fā)者想要在代碼中使用線程池還是比較簡單的,這得益于Java給我們封裝好的一系列API。但是,這些API的背后是什么呢,讓我們來揭開這個迷霧,看清線程池的本質。

線程池構造函數(shù)

通常,一般構造函數(shù)會反映出這個工具或這個對象的數(shù)據(jù)存儲結構。

如果把線程池比作一個公司。公司會有正式員工處理正常業(yè)務,如果工作量大的話,會雇傭外包人員來工作。

閑時就可以釋放外包人員以減少公司管理開銷。一個公司因為成本關系,雇傭的人員始終是有最大數(shù)。

如果這時候還有任務處理不過來,就走需求池排任務。

acc : 獲取調用上下文

corePoolSize: 核心線程數(shù)量,可以類比正式員工數(shù)量,常駐線程數(shù)量。

maximumPoolSize: 最大的線程數(shù)量,公司最多雇傭員工數(shù)量。常駐+臨時線程數(shù)量。

workQueue:多余任務等待隊列,再多的人都處理不過來了,需要等著,在這個地方等。

keepAliveTime:非核心線程空閑時間,就是外包人員等了多久,如果還沒有活干,解雇了。

threadFactory: 創(chuàng)建線程的工廠,在這個地方可以統(tǒng)一處理創(chuàng)建的線程的屬性。每個公司對員工的要求不一樣,恩,在這里設置員工的屬性。

handler:線程池拒絕策略,什么意思呢?就是當任務實在是太多,人也不夠,需求池也排滿了,還有任務咋辦?默認是不處理,拋出異常告訴任務提交者,我這忙不過來了。

添加一個任務

接著,我們看一下線程池中比較重要的execute方法,該方法用于向線程池中添加一個任務。

核心模塊用紅框標記了。

第一個紅框:workerCountOf方法根據(jù)ctl的低29位,得到線程池的當前線程數(shù),如果線程數(shù)小于corePoolSize,則執(zhí)行addWorker方法創(chuàng)建新的線程執(zhí)行任務;

第二個紅框:判斷線程池是否在運行,如果在,任務隊列是否允許插入,插入成功再次驗證線程池是否運行,如果不在運行,移除插入的任務,然后拋出拒絕策略。如果在運行,沒有線程了,就啟用一個線程。

第三個紅框:如果添加非核心線程失敗,就直接拒絕了。

這里邏輯稍微有點復雜,畫了個流程圖僅供參考

接下來,我們看看如何添加一個工作線程的?

添加worker線程

從方法execute的實現(xiàn)可以看出:addWorker主要負責創(chuàng)建新的線程并執(zhí)行任務,代碼如下(這里代碼有點長,沒關系,也是分塊的,總共有5個關鍵的代碼塊):

第一個紅框:做是否能夠添加工作線程條件過濾:

判斷線程池的狀態(tài),如果線程池的狀態(tài)值大于或等SHUTDOWN,則不處理提交的任務,直接返回;

第二個紅框:做自旋,更新創(chuàng)建線程數(shù)量:

通過參數(shù)core判斷當前需要創(chuàng)建的線程是否為核心線程,如果core為true,且當前線程數(shù)小于corePoolSize,則跳出循環(huán),開始創(chuàng)建新的線程

有人或許會疑問 retry 是什么?這個是java中的goto語法。只能運用在break和continue后面。

接著看后面的代碼:

第一個紅框:獲取線程池主鎖。

線程池的工作線程通過Woker類實現(xiàn),通過ReentrantLock鎖保證線程安全。

第二個紅框:添加線程到workers中(線程池中)。

第三個紅框:啟動新建的線程。

接下來,我們看看workers是什么。

一個hashSet。所以,線程池底層的存儲結構其實就是一個HashSet。

worker線程處理隊列任務

第一個紅框:是否是第一次執(zhí)行任務,或者從隊列中可以獲取到任務。

第二個紅框:獲取到任務后,執(zhí)行任務開始前操作鉤子。

第三個紅框:執(zhí)行任務。

第四個紅框:執(zhí)行任務后鉤子。

這兩個鉤子(beforeExecute,afterExecute)允許我們自己繼承線程池,做任務執(zhí)行前后處理。

到這里,源代碼分析到此為止。接下來做一下簡單的總結。

總結

所謂線程池本質是一個hashSet。多余的任務會放在阻塞隊列中。

只有當阻塞隊列滿了后,才會觸發(fā)非核心線程的創(chuàng)建。所以非核心線程只是臨時過來打雜的。直到空閑了,然后自己關閉了。

線程池提供了兩個鉤子(beforeExecute,afterExecute)給我們,我們繼承線程池,在執(zhí)行任務前后做一些事情。

線程池原理關鍵技術:鎖(lock,cas)、阻塞隊列、hashSet(資源池)

最后希望對你理解線程池有幫助。最后,留一個思考題,為什么線程池的底層數(shù)據(jù)接口采用HashSet來實現(xiàn)?

1、具有1-5工作經(jīng)驗的,面對目前流行的技術不知從何下手,

需要突破技術瓶頸的可以加。

2、在公司待久了,過得很安逸,

但跳槽時面試碰壁。

需要在短時間內進修、跳槽拿高薪的可以加。

3、如果沒有工作經(jīng)驗,但基礎非常扎實,對java工作機制,

常用設計思想,常用java開發(fā)框架掌握熟練的,可以加。

4、覺得自己很牛B,一般需求都能搞定。

但是所學的知識點沒有系統(tǒng)化,很難在技術領域繼續(xù)突破的可以加。

5. 群號:高級架構群 Java進階群:180705916.備注好信息!送架構視頻。

6.阿里Java高級大牛直播講解知識點,分享知識,

多年工作經(jīng)驗的梳理和總結,帶著大家全面、

科學地建立自己的技術體系和技術認知!

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 第一集 莫若卿是一名在岸巖大學的大學生她今年已經(jīng)十八歲了。他的妹妹叫莫若安。也有十八芳齡了。莫若卿很苦惱,有一個妹...
    劉芮汐因為有你閱讀 204評論 0 0
  • 今天小小馬特別勇敢,他做了人生中的第一個手術,雖然是個小手術,但需要一個人進入手術室進行全身麻醉,他沒有表現(xiàn)出一丁...
    batheny閱讀 245評論 1 1
  • 只為認識真實自己 大腦是如何做出決策呢?(四條主線) 我們所做的每個決策是否理性呢? 什么樣的決策 是相對理性的。...
    媽呀作業(yè)終于寫完了閱讀 375評論 0 0

友情鏈接更多精彩內容