線程池核心知識(shí)點(diǎn)

—讀《java并發(fā)編程》筆記

為什么需要線程執(zhí)行框架

不用線程池是否也有異步執(zhí)行任務(wù)的方案?

有兩種方案,一是單獨(dú)起一個(gè)線程,任務(wù)由這個(gè)線程順序執(zhí)行。二是每個(gè)任務(wù)創(chuàng)建一個(gè)新線程,每個(gè)任務(wù)都由一個(gè)新線程去執(zhí)行。

然而兩種方案各有缺點(diǎn):
第一種方案,因?yàn)槭琼樞驁?zhí)行,在任務(wù)的響應(yīng)效率有較大影響。
第二種方案,創(chuàng)建線程是有資源消耗的,對(duì)于web應(yīng)用這樣的大流量請(qǐng)求,很容易就會(huì)達(dá)到資源瓶頸。

另外需要考慮的一些問題:

  • 可否知道當(dāng)前任務(wù)在被哪個(gè)線程運(yùn)行了。
  • 任務(wù)的執(zhí)行順序是怎樣的,先入先出?優(yōu)先隊(duì)列?
  • 多少任務(wù)正在同時(shí)執(zhí)行
  • 如果當(dāng)前已經(jīng)達(dá)到了系統(tǒng)性能瓶頸,怎么決定任務(wù)的優(yōu)先級(jí),哪些任務(wù)需要被移出執(zhí)行隊(duì)列。
  • 任務(wù)執(zhí)行前的準(zhǔn)備,以及執(zhí)行后的清理工作(釋放資源)如何做。

為解決上面這些問題,客觀上需要有一個(gè)管理線程資源的框架。這個(gè)框架可以優(yōu)化線程執(zhí)行所占資源,定制靈活的執(zhí)行策略,讓異步任務(wù)的執(zhí)行更為健壯。

線程池及其創(chuàng)建

在java體系中,管理線程資源的框架便是線程池(thread pool)。線程池,顧名思義就是線程的資源池,是一種容器資源。它的主要作用就是讓線程可以重用,并且保持一定數(shù)量的活躍線程,從而使任務(wù)響應(yīng)時(shí)間縮短,通過對(duì)線程池運(yùn)行參數(shù)的調(diào)優(yōu),可以達(dá)到任務(wù)吞吐量和相應(yīng)時(shí)間的最優(yōu)。

線程池的創(chuàng)建,一般情況下,是通過concurrent包提供的工廠方法Executors
比如
Executors.newFixedThreadPool(int nThreads) 會(huì)返回一個(gè)固定線程數(shù)量的實(shí)現(xiàn)了ExecutorService接口的線程池服務(wù),如果當(dāng)前任務(wù)的提交數(shù)量超過了這個(gè)限定數(shù)量,會(huì)將其排入一個(gè)LinkedBlockingQueue中排隊(duì)。
除此之外,還有
Executors.newSingleThreadExecutor, Executors.newCachedThreadPool 等等

當(dāng)然,如果看到過Executors 的源代碼, 你就知道,還可以自己創(chuàng)建一個(gè)線程池,比如上述Executors.newFixedThreadPool(int nThreads) 其源碼就是
return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>(),threadFactory);

線程池的生命周期

線程池的生命周期有三個(gè)階段,首先是running 然后是 shut down 最終是terminated

  • running 顧名思義就是正常運(yùn)行狀態(tài)
  • shut down 執(zhí)行shutdownNow()后達(dá)到的狀態(tài),這個(gè)狀態(tài)下線程池不再接受新任務(wù),等待任務(wù)也阻*止。但是此時(shí)任務(wù)不一定運(yùn)行完,事實(shí)上這個(gè)方法會(huì)返回一個(gè)list包括了還在運(yùn)行的任務(wù)列表。
  • terminated 就是在shutdown后所有任務(wù)已經(jīng)完成的狀態(tài),此時(shí)沒有任務(wù)在運(yùn)行了。

線程池的參數(shù)

  1. corePoolSize 核心線程數(shù)。這個(gè)參數(shù)的含義是線程池需要保持的最低線程數(shù),不管當(dāng)前有沒有任務(wù)在運(yùn)行,線程池中都會(huì)保持這個(gè)配置數(shù)量的活躍線程。當(dāng)任務(wù)數(shù)量超過corePoolSize時(shí),會(huì)被丟到工作隊(duì)列中,直到隊(duì)列滿之前,線程池中的線程數(shù)不會(huì)增加。
  2. maxPoolSize :最大線程數(shù)。該參數(shù)指明了一個(gè)線程池中同時(shí)可以有多少活躍線程同時(shí)運(yùn)行。
  3. keepAliveTime 線程最大存活時(shí)間。 當(dāng)池子中的線程數(shù)量超過了corePoolSize時(shí),這個(gè)數(shù)值代表了那些超出的空閑線程可以存活的最大時(shí)間。
  4. workQueue:自定義的線程池隊(duì)列實(shí)例。有三種隊(duì)列類型可以選擇,分別是無界隊(duì)列,有界隊(duì)列,以及 同步隊(duì)列(SynchronousQueue),其中Executors.newFixedThreadPool 使用的LinkedBlockingQueue 屬于無界隊(duì)列, Executors.newCachedThreadPool 使用的是同步隊(duì)列。其中,使用默認(rèn)的無界隊(duì)列,可能會(huì)存在在并發(fā)量比較高時(shí),隊(duì)列占用內(nèi)存過高可能導(dǎo)致其溢出的風(fēng)險(xiǎn)。
    queue的配置可以同前面幾個(gè)參數(shù)配合,以達(dá)到不同的效果:
    比如:
    • 按照優(yōu)先級(jí)處理一組數(shù)據(jù),可以傳入PriorityQueue 根據(jù)指定參數(shù)配置優(yōu)先級(jí), 這個(gè)時(shí)候隊(duì)列長隊(duì)可以設(shè)置相對(duì)較長,而corePoolSize可以設(shè)置相對(duì)小,從而達(dá)到吞吐量與占用資源的最優(yōu)配置。
    • 對(duì)于大量短時(shí)間訪問的請(qǐng)求,考慮用SynchronousQueue。同時(shí)設(shè)置一個(gè)相對(duì)較短的keepAliveTime以及極大的maxPoolSize, SynchronousQueue的特性是如果要把一個(gè)元素加入隊(duì)列,需要有另外一個(gè)線程等待接收,如果另外一個(gè)線程沒有,則創(chuàng)建一個(gè)。這個(gè)特性很適合處理即時(shí)的消息傳遞,可以支撐較大的容量。
  5. RejectedExecutionHandler: 隊(duì)列飽和處理器。 當(dāng)工作隊(duì)列已經(jīng)滿時(shí),要決定哪些任務(wù)保留哪些任務(wù)要丟棄,有幾種策略可以選擇,比如:AbortPolicy, CallerRunsPolicy,DiscardPolicy。 可以根據(jù)實(shí)際情況靈活選擇。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容