自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

假如我是一個(gè)線程池

開發(fā) 前端
我是一個(gè)線程池(ThreadPoolExecutor),我的主要工作是管理在我這的多個(gè)線程(Thread),讓他們能并發(fā)地執(zhí)行多個(gè)任務(wù)的同時(shí),又不會(huì)造成很大的的系統(tǒng)開銷,有人不明白,創(chuàng)建線程有啥開銷呢,不是只要 new 一個(gè) Thread 出來讓它跑就行了嗎?

[[348770]]

線程池的自我介紹

我是一個(gè)線程池(ThreadPoolExecutor),我的主要工作是管理在我這的多個(gè)線程(Thread),讓他們能并發(fā)地執(zhí)行多個(gè)任務(wù)的同時(shí),又不會(huì)造成很大的的系統(tǒng)開銷,有人不明白,創(chuàng)建線程有啥開銷呢,不是只要 new 一個(gè) Thread 出來讓它跑就行了嗎,這里我要簡(jiǎn)單解釋下:

  1. 其實(shí) Java 中的線程模型是基于操作系統(tǒng)原生線程模型實(shí)現(xiàn)的,也就是說 Java 中的線程其實(shí)是基于內(nèi)核線程實(shí)現(xiàn)的,線程的創(chuàng)建,析構(gòu)與同步都需要進(jìn)行系統(tǒng)調(diào)用,而系統(tǒng)調(diào)用需要在用戶態(tài)與內(nèi)核中來回切換,代價(jià)相對(duì)較高,線程的生命周期包括「線程創(chuàng)建時(shí)間」,「線程執(zhí)行任務(wù)時(shí)間」,「線程銷毀時(shí)間」,創(chuàng)建和銷毀都需要導(dǎo)致系統(tǒng)調(diào)用。
  2. 每個(gè) Thread 都需要有一個(gè)內(nèi)核線程的支持,也就意味著每個(gè) Thread 都需要消耗一定的內(nèi)核資源(如內(nèi)核線程的??臻g),因?yàn)槟軇?chuàng)建的 Thread 是有限的,默認(rèn)一個(gè)線程的線程棧大小是 1 M,如果每來一個(gè)任務(wù)就創(chuàng)建線程的話,1024 個(gè)任務(wù)就光創(chuàng)建線程就占用了 1 G 內(nèi)存,很容易就系統(tǒng)崩潰了。

corePoolSize

所以我的主要作用就是減少線程的創(chuàng)建時(shí)間和銷毀時(shí)間,線程創(chuàng)建后不讓它馬上銷毀,而是常駐在我這,隨叫隨到,我把這些常駐的線程叫做核心線程,核心線程數(shù)也不宜過多,所以我指定了它們的數(shù)量(corePoolSize),假定為 3 吧。

「線程池,這是我的一個(gè)任務(wù),幫我執(zhí)行一下吧」,主線程丟給我任務(wù)后立馬返回,于是我趕緊調(diào)用 execute 方法來處理丟給我的這個(gè)任務(wù)(Runnable)

  1. public interface Executor { 
  2.     void execute(Runnable command); 

由于我誕生后還沒有執(zhí)行過任務(wù),核心線程一直為 0,于是在這個(gè)方法里我創(chuàng)建了一個(gè)線程作為核心線程。

「線程池,任務(wù)又來了,幫我執(zhí)行一下吧」,又來任務(wù)了!于是我再次調(diào)用了 execute,又創(chuàng)建了一個(gè)核心線程,此時(shí)核心線程數(shù)為 2。

過了一段時(shí)間,第一個(gè)核心線程已經(jīng)執(zhí)行完任務(wù),空閑出來了,此時(shí)任務(wù)又來了。。。

「線程池,這是我的一個(gè)任務(wù),幫我執(zhí)行一下吧」主線程摞下一句話后又走了,此時(shí)是 1 個(gè)核心線程在忙碌,一個(gè)核心線程空閑,可能很多人誤以為這里既然有一個(gè)核心線程在空閑,那就把任務(wù)交給這個(gè)線程處理即可,不用再創(chuàng)建核心線程了,但實(shí)際上只要當(dāng)前核心線程數(shù)少于當(dāng)初設(shè)置的 corePoolSize,不管當(dāng)前核心線程是否空閑,我依然會(huì)再創(chuàng)建一個(gè)核心線程,主要是為了保證核心線程盡快達(dá)到我們?cè)O(shè)置的數(shù)量,這樣如果之后有很多任務(wù)涌進(jìn)來,這些已創(chuàng)建好的核心線程就可以馬上準(zhǔn)備好處理這些任務(wù)了,不需要再經(jīng)過創(chuàng)建線程這種耗時(shí)的操作了。

經(jīng)過上面的一番操作,核心線程數(shù)來到了最開始設(shè)置的數(shù)量 3 了。

workQueue

「線程池,任務(wù)又來了,幫我執(zhí)行一下吧」,熟悉的聲音又來了,此時(shí)核心線程已經(jīng)達(dá)到了我們?cè)O(shè)置的數(shù)量 3 個(gè)了,再創(chuàng)建線程當(dāng)然可以,但又要造成一個(gè)系統(tǒng)調(diào)用,開銷比較大,其實(shí)核心線程可能經(jīng)過很短的時(shí)間又能馬上空閑出來了,不如把任務(wù)放到放到一個(gè)隊(duì)列里,讓這些核心線程自己去取。

 

聰明的你一定發(fā)現(xiàn)了,這就是典型的生產(chǎn)者-消費(fèi)者模型,線程池中的線程只要不斷循環(huán)去 workQueue 隊(duì)列獲取任務(wù)即可,為了避免 workQueue 為空線程一直輪詢導(dǎo)致的 CPU 資源被占用的問題,這里的 workQueue 采用了阻塞隊(duì)列,所謂阻塞是指,如果 workQueue 為空,則獲取元素的線程會(huì)等待隊(duì)列變?yōu)榉强眨坏┯行碌娜蝿?wù)入隊(duì)列,會(huì)喚醒等待中的線程。

畫外音:線程等待是指調(diào)用 LockSupport.park 將線程從運(yùn)行態(tài)變?yōu)樽枞麘B(tài),此時(shí)線程就不占用 CPU 資源了

可是好景不長(zhǎng), JVM 老大向我反饋出現(xiàn) OOM 問題了,一看問題我就明白了,原來是哪個(gè)新手程序員在創(chuàng)建我的時(shí)候,聲明使用了無界隊(duì)列,導(dǎo)致核心線程無法及時(shí)處理任務(wù),而任務(wù)又源源不斷地添加進(jìn)了 workQueue 中(即生產(chǎn)任務(wù)速度遠(yuǎn)大于消費(fèi)任務(wù)速度),導(dǎo)致 workQueue 越來越大,最終產(chǎn)生了 OOM!

解決方式很簡(jiǎn)單,使用有界隊(duì)列即可,這樣當(dāng) workQueue 滿時(shí)就無法添加任務(wù)了,不會(huì)導(dǎo)致 workQueue 無限增大導(dǎo)致 OOM。

畫外音:所謂有界隊(duì)列是指設(shè)定了固定大小的隊(duì)列,當(dāng)隊(duì)列里的元素超過這個(gè)大小后就再也不能往這個(gè)隊(duì)列里塞任務(wù)了,而無界隊(duì)列由于沒有設(shè)置固定大小 ,可以直接入隊(duì),直到溢出,容易造成 OOM,所以創(chuàng)建線程池時(shí)應(yīng)該盡量使用有界隊(duì)列

maximumPoolSize

將 workQueue 改用有界隊(duì)列后,再也沒出現(xiàn)過 OOM 了,不過由于主線程又源源不斷地丟了一些耗時(shí)的任務(wù)過來,核心線程依然處理不過來,workQueue 很快又滿了,這時(shí)我想起了另一個(gè)參數(shù) maximumPoolSize,這個(gè)參數(shù)定義了我能創(chuàng)建的最大線程數(shù),當(dāng)其它線程要往隊(duì)列塞任務(wù),但發(fā)現(xiàn) workQueue 滿時(shí),由于當(dāng)前在我這的線程還未到達(dá) maximumPoolSize(假設(shè)起初指定為 5),所以我又創(chuàng)建了線程來處理這個(gè)任務(wù)。

畫外音: 在 workQueue 已滿的條件下,如果當(dāng)前線程池的線程數(shù)量 >= corePoolSize 且 <= maximumPoolSize,后續(xù)如果一直有其它線程丟任務(wù)進(jìn)來,會(huì)一直創(chuàng)建線程,直到 maximumPoolSize。

RejectedExecutionHandler

某天,往我這丟任務(wù)的某個(gè)線程反饋收到異常了,我一看,我靠,workQueue 滿了,線程數(shù)也達(dá)到了 maximumPoolSize,但此時(shí)依然有任務(wù)不斷往 workQueue 中插,但這種情況下已經(jīng)超出了我的處理能力了,只好執(zhí)行默認(rèn)的拒絕策略,拋出 RejectedExecutionException 異常讓其他線程(往我這丟任務(wù)的線程)自己處理。

畫外音:線程池提供了 AbortPolicy,DiscardPolicy,DiscardOldestPolicy,CallerRunsPolicy,自定義這五種拒絕策略,默認(rèn)是 AbortPolicy

keepAliveTime

在線程們的努力之下,workQueue 隊(duì)列中的任務(wù)很快被清空了,很長(zhǎng)一段時(shí)間都沒有任務(wù)進(jìn)來了,線程們很快就無事可做,放著又占用資源,該怎么處理呢?此時(shí)我這有核心線程 3(corePoolSize = 3), 額外線程 2 (maximumPoolSize 為 5),

我是這么處理的,如果當(dāng)前線程總數(shù)超過了 corePoolSize,在 keepAliveTime 這個(gè)時(shí)間內(nèi),如果池子里的線程一直空閑,就把這個(gè)線程給干掉,哪個(gè)線程空閑時(shí)間先到達(dá) keepAliveTime,就干掉哪個(gè),直到線程數(shù)減少到 corePoolSize。

畫外音:線程池里沒有核心線程和額外線程之分,只是為了講述方便人為劃分了一下,但其實(shí)線程池里的線程都是平等的,任何一個(gè)線程都可以被干掉

本文轉(zhuǎn)載自微信公眾號(hào)「碼?!?,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系碼海公眾號(hào)。

 

 

責(zé)任編輯:武曉燕 來源: 碼海
相關(guān)推薦

2020-04-20 09:02:33

函數(shù)RPCCPU

2019-03-28 10:09:49

內(nèi)存CPU硬盤

2018-06-15 16:17:08

2022-11-02 09:53:54

架構(gòu)核酸

2023-03-03 21:25:28

馬斯克特斯拉

2022-03-09 09:43:01

工具類線程項(xiàng)目

2020-04-09 09:02:38

bug編程代碼

2021-03-29 08:47:24

線程面試官線程池

2022-03-07 05:53:41

線程CPU代碼

2021-10-27 06:49:34

線程池Core函數(shù)

2023-03-08 07:43:07

DUCC配置平臺(tái)

2022-02-10 11:43:54

DUBBO線程池QPS

2021-04-18 07:12:08

Dubbo線程池

2022-05-19 14:49:19

Nick網(wǎng)絡(luò)開源社區(qū)專有網(wǎng)絡(luò)

2016-12-15 08:54:52

線程sessionopenSession

2022-12-30 08:29:07

Nacos動(dòng)態(tài)化線程池

2012-11-01 13:41:25

編程語言BasicPerl

2024-11-08 14:11:09

2024-02-04 09:19:00

Nacos動(dòng)態(tài)化線程池

2018-12-18 09:54:30

點(diǎn)贊
收藏

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