Java線程池原理
線程Thread 其實(shí)是一個(gè)重量級(jí)資源,它的創(chuàng)建、啟動(dòng)以及銷毀都是比較耗費(fèi)資源的,而且一個(gè)系統(tǒng)中創(chuàng)建的線程數(shù)量是有限的,線程數(shù)量和系統(tǒng)性能其實(shí)是一個(gè)拋物線關(guān)系,當(dāng)線程數(shù)量達(dá)到某個(gè)數(shù)值的時(shí)候,性能反而會(huì)下降很多,所以對(duì)于線程的管理,尤其是線程數(shù)量的控制能直接決定程序的性能。

圖片引用:https://blog.csdn.net/odailidong/article/details/47265123
1、線程池概念
通過上圖我們分析線程數(shù)量和系統(tǒng)性能是成拋物線類似的關(guān)系的,那么如何管理線程數(shù)量來達(dá)到最佳的系統(tǒng)性能,線程池便產(chǎn)生了。
線程池:通俗的理解就是一個(gè)池子,里面存放著一些已經(jīng)創(chuàng)建好的線程,當(dāng)有任務(wù)提交到線程池執(zhí)行時(shí),池子中的某個(gè)線程會(huì)主動(dòng)的執(zhí)行該任務(wù)。如果池子中的線程數(shù)量不夠應(yīng)付數(shù)量眾多的任務(wù)時(shí),則需要自動(dòng)擴(kuò)充新的線程到線程池中,但是池中的線程是有最大數(shù)量限制的,當(dāng)任務(wù)比較少的時(shí)候,線程池中的線程能夠自動(dòng)回收,釋放資源。

?
一個(gè)完整的線程池必須具備以下幾個(gè)模塊:
①、任務(wù)隊(duì)列
用于緩存提交的任務(wù)。
②、最大任務(wù)數(shù)量QueueSize
為了防止任務(wù)過多造成的內(nèi)存溢出,必須限定任務(wù)的最大數(shù)量。
③、線程池參數(shù)
1、初始線程數(shù)量init:也就是創(chuàng)建線程池時(shí)預(yù)先創(chuàng)建好一定數(shù)量的線程。
2、最大線程數(shù)量max:因?yàn)榫€程不夠用時(shí),線程池可以自動(dòng)創(chuàng)建新的線程填充到線程池,但是不能超過線程池最大線程數(shù)量。
3、核心線程數(shù)量core:當(dāng)任務(wù)比較寬松,線程池需要釋放一定的線程數(shù)量,但是最少要保證一定數(shù)量的線程數(shù),這個(gè)線程數(shù)是核心線程數(shù)(也稱為活躍線程數(shù))。
④、任務(wù)拒絕策略
當(dāng)線程池?cái)?shù)量已經(jīng)達(dá)到最大線程數(shù)量,并且任務(wù)隊(duì)列也滿了,則需要相應(yīng)的拒絕策略來通知任務(wù)提交者。
⑤、線程工廠
主要用于個(gè)性化定制線程,比如將線程設(shè)置為守護(hù)線程以及設(shè)置線程名稱等。
⑥、KeepAliveTime
線程池線程數(shù)超過 core 數(shù)量空閑的線程會(huì)在?keepAliveTime
?指定的時(shí)間后自動(dòng)銷毀,終保持到?core
?大小
2、線程池的作用
①、降低資源消耗
通過重復(fù)利用已創(chuàng)建的線程降低線程創(chuàng)建和銷毀造成的消耗。
②、提高響應(yīng)速度
當(dāng)任務(wù)到達(dá)時(shí),任務(wù)可以不需要等到線程創(chuàng)建完成就能立即使用。
③、提高線程的可管理性
線程是稀缺資源,如果無(wú)限制地創(chuàng)建,不僅會(huì)消耗系統(tǒng)資源,還會(huì)降低系統(tǒng)的穩(wěn)定性,使用線程池可以進(jìn)行統(tǒng)一分配、調(diào)優(yōu)和監(jiān)控。
3、JDK線程池框架

①、Executor
執(zhí)行器接口。
該接口是Java線程池最上層父接口,該接口只有一個(gè) execute 方法,作用是定義執(zhí)行Runnable任務(wù)的方式
View Code
②、ExecutorService
定義提供對(duì)Executor的服務(wù)的接口。
該接口繼承于 Executor 接口,添加了shutdown、shutdownAll、submit、invokeAll等一系列對(duì)線程的操作方法,增加Executor的行為
③、Executors
這是一個(gè)靜態(tài)工廠類,該類定義了一系列靜態(tài)工廠方法,通過這些工廠方法可以返回各種不同的線程池。主要有如下四種:newCachedThreadPool、newFixedThreadPool 、newScheduledThreadPool 、newSingleThreadExecutor 。下面我們會(huì)詳細(xì)介紹。
④、AbstractExecutorService
這是一個(gè)抽象類,實(shí)現(xiàn)ExecuotrService接口。
⑤、ThreadPoolExecutor
這是線程池最核心的一個(gè)類,各種線程池的實(shí)現(xiàn)都是基于這個(gè)類。下面是這個(gè)類的構(gòu)造方法:
public ThreadPoolExecutor(int corePoolSize, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?int maximumPoolSize, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?long keepAliveTime, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?TimeUnit unit, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?BlockingQueue<Runnable> workQueue) { ? ? ? ?this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, ? ? ? ? ? ? Executors.defaultThreadFactory(), defaultHandler); ? ?}
定義了我們上面所說的一個(gè)線程池需要具備的各種模塊,包括任務(wù)隊(duì)列workQueue,核心線程池?cái)?shù)量corePoolSize,最大線程池?cái)?shù)量maximumPoolSize等。
?⑥、ScheduledThreadPoolExecutor
ScheduledThreadPoolExecutor繼承了ThreadPoolExecutor,實(shí)現(xiàn)了ScheduledExecutorService。在線程池的基礎(chǔ)上,實(shí)現(xiàn)了可調(diào)度的線程池功能,比如指定延時(shí)執(zhí)行任務(wù),再比如周期性重復(fù)執(zhí)行任務(wù)等。
?4、四種常用線程池
前面我們講過通過?Executors 這個(gè)靜態(tài)工廠類方法能夠產(chǎn)生各種不同的線程池,下面我們分別來介紹幾種常用的線程池。
①、newCachedThreadPool
創(chuàng)建一個(gè)線程池,根據(jù)需要?jiǎng)?chuàng)建新的線程,并且能夠重用先前創(chuàng)建的線程。
這個(gè)線程池在執(zhí)行?大量短生命周期的異步任務(wù)時(shí)(many short-lived asynchronous task),可以顯著提高程序性能。調(diào)用?execute?時(shí),可以重用之前已構(gòu)造的可用線程,如果不存在可用線程,那么會(huì)重新創(chuàng)建一個(gè)新的線程并將其加入到線程池中。如果線程超過 60 秒還未被使用,就會(huì)被中止并從緩存中移除。因此,線程池在長(zhǎng)時(shí)間空閑后不會(huì)消耗任何資源。
View Code
范例:重復(fù)利用線程
View Code
結(jié)果:

②、newFixedThreadPool
創(chuàng)建一個(gè)定長(zhǎng)線程池,可控制線程最大并發(fā)數(shù),超出的線程會(huì)在隊(duì)列中等待。
這個(gè)實(shí)例會(huì)復(fù)用?固定數(shù)量的線程?處理一個(gè)?共享的無(wú)邊界隊(duì)列?。任何時(shí)間點(diǎn),最多有 nThreads 個(gè)線程會(huì)處于活動(dòng)狀態(tài)執(zhí)行任務(wù)。如果當(dāng)所有線程都是活動(dòng)時(shí),有多的任務(wù)被提交過來,那么它會(huì)一致在隊(duì)列中等待直到有線程可用。如果任何線程在執(zhí)行過程中因?yàn)殄e(cuò)誤而中止,新的線程會(huì)替代它的位置來執(zhí)行后續(xù)的任務(wù)。所有線程都會(huì)一致存于線程池中,直到顯式的執(zhí)行 ExecutorService.shutdown() 關(guān)閉。
范例:控制最大并發(fā)數(shù)(最大線程數(shù))
View Code
結(jié)果:

③、newScheduledThreadPool?
創(chuàng)建一個(gè)定長(zhǎng)線程池,支持定時(shí)及周期性任務(wù)執(zhí)行。
即使線程都是空閑的,也會(huì)保持一定數(shù)量的核心線程池在里面。
1 public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {2 ? ? ? ? return new ScheduledThreadPoolExecutor(corePoolSize);3 ? ? }
范例:線程延遲3秒鐘執(zhí)行
View Code
④、newSingleThreadScheduledExecutor
創(chuàng)建一個(gè)單線程化的線程池,它只會(huì)用唯一的工作線程來執(zhí)行任務(wù),保證所有任務(wù)按照指定順序(FIFO, LIFO, 優(yōu)先級(jí))執(zhí)行。
這個(gè)實(shí)例只會(huì)使用單個(gè)工作線程來執(zhí)行一個(gè)無(wú)邊界的隊(duì)列。(注意,如果單個(gè)線程在執(zhí)行過程中因?yàn)槟承╁e(cuò)誤中止,新的線程會(huì)替代它執(zhí)行后續(xù)線程)。它可以保證認(rèn)為是按順序執(zhí)行的,任何時(shí)候都不會(huì)有多于一個(gè)的任務(wù)處于活動(dòng)狀態(tài)。和 newFixedThreadPool(1) 的區(qū)別在于,如果線程遇到錯(cuò)誤中止,它是無(wú)法使用替代線程的。
范例:?jiǎn)尉€程運(yùn)行
View Code
結(jié)果:

?