成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

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

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

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

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

[[248230]]

池化技術(shù)

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

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

在編程領(lǐng)域,比較典型的池化技術(shù)有:

線程池、連接池、內(nèi)存池、對象池等。

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

創(chuàng)建一個線程

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

  1. public class App { 
  2.     public static void main(String[] args) throws Exception { 
  3.         new Thread(new Runnable() { 
  4.             @Override 
  5.             public void run() { 
  6.                 System.out.println("線程運行中"); 
  7.             } 
  8.         }).start(); 
  9.     } 

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

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

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

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

線程池的簡單使用

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

  1. import java.util.concurrent.*; 
  2.  
  3. public class App { 
  4.     public static void main(String[] args) throws Exception { 
  5.         ExecutorService executorService = new ThreadPoolExecutor(1, 1, 
  6.                 60L, TimeUnit.SECONDS, 
  7.                 new ArrayBlockingQueue<>(10)); 
  8.  
  9.         executorService.execute(new Runnable() { 
  10.             @Override 
  11.             public void run() { 
  12.                 System.out.println("abcdefg"); 
  13.             } 
  14.         }); 
  15.  
  16.         executorService.shutdown(); 
  17.     } 

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

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

線程池構(gòu)造函數(shù)

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

構(gòu)造函數(shù)

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

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

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

  • acc : 獲取調(diào)用上下文
  • corePoolSize: 核心線程數(shù)量,可以類比正式員工數(shù)量,常駐線程數(shù)量。
  • maximumPoolSize: ***的線程數(shù)量,公司最多雇傭員工數(shù)量。常駐+臨時線程數(shù)量。
  • workQueue:多余任務(wù)等待隊列,再多的人都處理不過來了,需要等著,在這個地方等。
  • keepAliveTime:非核心線程空閑時間,就是外包人員等了多久,如果還沒有活干,解雇了。
  • threadFactory: 創(chuàng)建線程的工廠,在這個地方可以統(tǒng)一處理創(chuàng)建的線程的屬性。每個公司對員工的要求不一樣,恩,在這里設(shè)置員工的屬性。
  • handler:線程池拒絕策略,什么意思呢?就是當(dāng)任務(wù)實在是太多,人也不夠,需求池也排滿了,還有任務(wù)咋辦?默認(rèn)是不處理,拋出異常告訴任務(wù)提交者,我這忙不過來了。

添加一個任務(wù)

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

源碼

核心模塊用紅框標(biāo)記了。

  • ***個紅框:workerCountOf方法根據(jù)ctl的低29位,得到線程池的當(dāng)前線程數(shù),如果線程數(shù)小于corePoolSize,則執(zhí)行addWorker方法創(chuàng)建新的線程執(zhí)行任務(wù);
  • 第二個紅框:判斷線程池是否在運行,如果在,任務(wù)隊列是否允許插入,插入成功再次驗證線程池是否運行,如果不在運行,移除插入的任務(wù),然后拋出拒絕策略。如果在運行,沒有線程了,就啟用一個線程。
  • 第三個紅框:如果添加非核心線程失敗,就直接拒絕了。

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

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

添加worker線程

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

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

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

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

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

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

接著看后面的代碼:

  • ***個紅框:獲取線程池主鎖。

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

  • 第二個紅框:添加線程到workers中(線程池中)。
  • 第三個紅框:啟動新建的線程。

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

一個hashSet。所以,線程池底層的存儲結(jié)構(gòu)其實就是一個HashSet。

worker線程處理隊列任務(wù)

  • ***個紅框:是否是***次執(zhí)行任務(wù),或者從隊列中可以獲取到任務(wù)。
  • 第二個紅框:獲取到任務(wù)后,執(zhí)行任務(wù)開始前操作鉤子。
  • 第三個紅框:執(zhí)行任務(wù)。
  • 第四個紅框:執(zhí)行任務(wù)后鉤子。

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

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

總結(jié)

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

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

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

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

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

本文來自作者投稿,原作者『林灣村龍貓』,Hollis做了些補(bǔ)充、調(diào)整及修改。

【本文是51CTO專欄作者Hollis的原創(chuàng)文章,作者微信公眾號Hollis(ID:hollischuang)】

戳這里,看該作者更多好文

責(zé)任編輯:武曉燕 來源: 51CTO專欄
相關(guān)推薦

2021-05-26 11:30:24

Java線程池代碼

2024-01-29 15:54:41

Java線程池公平鎖

2013-05-28 13:57:12

MariaDB

2025-02-24 08:00:00

線程池Java開發(fā)

2013-06-08 10:11:31

Java線程池架構(gòu)

2015-10-10 09:39:42

Java線程池源碼解析

2012-05-15 02:18:31

Java線程池

2022-11-09 09:01:08

并發(fā)編程線程池

2020-12-10 08:24:40

線程池線程方法

2017-02-27 10:43:07

Javasynchronize

2021-12-07 08:31:48

線程池中間件開源

2020-03-05 15:34:16

線程池C語言局域網(wǎng)

2021-07-16 11:35:20

Java線程池代碼

2025-06-23 00:00:02

線程池Java任務(wù)隊列

2023-10-13 00:09:20

桶排序排序算法

2023-10-08 00:02:07

Java排序算法

2025-04-16 08:50:00

信號量隔離線程池隔離并發(fā)控制

2012-02-01 11:20:23

Java線程

2021-03-06 22:41:06

內(nèi)核源碼CAS

2015-08-03 09:54:26

Java線程Java
點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 国产成人精品网站 | 中文字幕第一页在线 | av在线一区二区 | 免费爱爱视频 | 蜜臀久久99精品久久久久野外 | 亚州成人 | 免费观看a级毛片在线播放 黄网站免费入口 | 欧美福利网站 | 国产一区二区三区色淫影院 | 日日草夜夜草 | 亚欧精品| 中文字幕在线观看视频一区 | 综合在线视频 | 99久久久无码国产精品 | 久久综合久久久 | 2020国产在线 | 国产农村妇女精品一区 | 涩涩99| 午夜免费视频 | 久久久久久国产精品免费免费男同 | 亚洲精品亚洲人成人网 | 国产日韩欧美 | 成人在线精品 | 国产激情91久久精品导航 | 久久久久久999 | 天天干狠狠操 | 国产色网 | 日本在线观看视频 | 日韩免费一区二区 | 男女啪啪网址 | 国产精品久久久久久久久 | 亚洲一区二区av | 欧美中文字幕在线观看 | 亚洲国产偷 | 中文字幕在线视频一区二区三区 | 国产精品视频在线观看 | 精品国产不卡一区二区三区 | 在线观看国产精品视频 | 福利网站在线观看 | 欧美一区二区免费 | 国产日韩一区二区三免费高清 |