Java?ThreadPoolExecutor線程池有關(guān)介紹
為什么要有線程池?
在實(shí)際使用中,服務(wù)器在創(chuàng)建和銷毀線程上花費(fèi)的時間和消耗的系統(tǒng)資源都相當(dāng)大,所以要盡可能減少創(chuàng)建和銷毀線程的次數(shù)。
由于沒有線程創(chuàng)建和銷毀時的消耗,可以提高系統(tǒng)響應(yīng)速度
可以對線程進(jìn)行合理的管理
線程池狀態(tài)
1、RUNNING
狀態(tài)說明:線程池處于RUNNING狀態(tài)時,能夠接收新任務(wù)以及對已添加的任務(wù)進(jìn)行處理。
2、SHUTDOWN
狀態(tài)說明:線程池處于SHUTDOWN狀態(tài)時,不接收新任務(wù),但能處理已添加的任務(wù)
3、STOP
狀態(tài)說明:線程池處于STOP狀態(tài)時,不接收新任務(wù),不處理已添加的任務(wù),并且會中斷正在處理的任務(wù)
4、TIDYING
狀態(tài)說明:當(dāng)所有的任務(wù)已終止,ctl記錄的任務(wù)數(shù)為0,線程池的狀態(tài)會變?yōu)門IDYING狀態(tài);當(dāng)線程池的狀態(tài)變?yōu)門IDYING狀態(tài)時,會調(diào)用鉤子函數(shù)terminated(),該方法在ThreadPoolExecutor中是空的,若用戶想在線程池變?yōu)門IDYING時進(jìn)行相應(yīng)的處理,就需要重載terminated()函數(shù)實(shí)現(xiàn)。
當(dāng)線程池為STOP時,線程池中執(zhí)行的任務(wù)為空時,就會又STOP->TIDYING
5、TERMINATED
狀態(tài)說明:線程池徹底終止,就會變成TERMINATED狀態(tài)
ThreadPoolExecutor核心參數(shù)
corePoolSize
corePoolSize – the number of threads to keep in the pool, even if they are idle, unless allowCoreThreadTimeOut is set
池中持有的線程數(shù),即使它們處于空閑狀態(tài),除非設(shè)置了allowCoreThreadTimeOut
線程池中的核心線程數(shù),當(dāng)提交一個任務(wù)時,線程池創(chuàng)建一個新線程執(zhí)行任務(wù),直到當(dāng)前線程數(shù)等于corePoolSize, 即使有其他空閑線程能夠執(zhí)行新來的任務(wù), 也會繼續(xù)創(chuàng)建線程;
如果執(zhí)行了線程池的prestartAllCoreThreads()方法,線程池會提前創(chuàng)建并啟動所有核心線程。
案例:
核心線程數(shù)和最大線程數(shù)為1,使用一個不存儲元素的阻塞隊(duì)列。
public static void main(String[] args) throws InterruptedException { ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS, new SynchronousQueue<>(), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy()); for (int i = 0; i < 2; i++) { executor.execute(()->{ System.out.println(Thread.currentThread().getName()); }); Thread.sleep(1000); } }
輸出 :
pool-1-thread-1
pool-1-thread-1
maximumPoolSize
maximumPoolSize – the maximum number of threads to allow in the pool
池中允許存在的最大線程數(shù)
案例:
核心線程數(shù)是1,最大線程數(shù)為3,使用一個不存儲元素的阻塞隊(duì)列。(注意結(jié)合workQueue參數(shù)食用~)
public static void main(String[] args) throws InterruptedException { ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 3, 0, TimeUnit.SECONDS, new SynchronousQueue<>(), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy()); for (int i = 0; i < 3; i++) { executor.execute(()->{ System.out.println(Thread.currentThread().getName()); }); } }
輸出:
pool-1-thread-1
pool-1-thread-3
pool-1-thread-2
keepAliveTime
keepAliveTime – when the number of threads is greater than the core, this is the maximum time that excess idle threads will wait for new tasks before terminating.
當(dāng)線程數(shù)大于核心時,這是多余空閑線程在終止前等待新任務(wù)的最長時間。
線程空閑時的存活時間,即當(dāng)線程沒有任務(wù)執(zhí)行時,該線程繼續(xù)存活的時間;默認(rèn)情況下,該參數(shù)只在線程數(shù)大于corePoolSize時才有用, 超過這個時間的空閑線程將被終止;
unit
unit – the time unit for the keepAliveTime argument
keepAliveTime參數(shù)的單位
workQueue
workQueue – the queue to use for holding tasks before they are executed. This queue will hold only the Runnable tasks submitted by the execute method.
用來放置沒有執(zhí)行的任務(wù),此隊(duì)列將僅保存execute方法提交的可運(yùn)行任務(wù)。
用來保存等待被執(zhí)行的任務(wù)的阻塞隊(duì)列。
如果當(dāng)前線程數(shù)為corePoolSize,繼續(xù)提交的任務(wù)被保存到阻塞隊(duì)列中,等待被執(zhí)行;
如果當(dāng)前阻塞隊(duì)列滿了,且繼續(xù)提交任務(wù),則創(chuàng)建新的線程執(zhí)行任務(wù),前提是當(dāng)前線程數(shù)小于maximumPoolSize;當(dāng)阻塞隊(duì)列是無界隊(duì)列, 則maximumPoolSize則不起作用, 因?yàn)闊o法提交至核心線程池的線程會一直持續(xù)地放入workQueue。
JDK提供以下隊(duì)列:
- ArrayBlockingQueue: 基于數(shù)組結(jié)構(gòu)的有界阻塞隊(duì)列,按FIFO排序任務(wù);(常用)
- LinkedBlockingQueue: 基于鏈表結(jié)構(gòu)的阻塞隊(duì)列,按FIFO排序任務(wù),吞吐量通常要高于ArrayBlockingQueue;(常用)
- SynchronousQueue: 一個不存儲元素的阻塞隊(duì)列,每個插入操作必須等到另一個線程調(diào)用移除操作,否則插入操作一直處于阻塞狀態(tài),吞吐量通常要高于LinkedBlockingQueue;(常用)
- PriorityBlockingQueue: 具有優(yōu)先級的無界阻塞隊(duì)列;
- DelayQueue:一個使用優(yōu)先級隊(duì)列實(shí)現(xiàn)的無界阻塞隊(duì)列。
- LinkedTransferQueue:一個由鏈表結(jié)構(gòu)組成的無界阻塞隊(duì)列。
- LinkedBlockingDeque:一個由鏈表結(jié)構(gòu)組成的雙向阻塞隊(duì)列。
案例:
核心線程數(shù)是1,最大線程數(shù)為3,使用一個容量為1的隊(duì)列。
public static void main(String[] args) throws InterruptedException { ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 3, 0, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy()); for (int i = 0; i < 3; i++) { executor.execute(()->{ System.out.println(Thread.currentThread().getName()); }); } }
輸出:
pool-1-thread-2
pool-1-thread-1
pool-1-thread-2
threadFactory
threadFactory – the factory to use when the executor creates a new thread
創(chuàng)建執(zhí)行器創(chuàng)建線程的工廠
通過自定義的線程工廠可以給每個新建的線程設(shè)置一個具有識別度的線程名。默認(rèn)為DefaultThreadFactory。
案例:
給線程起名字。我是用spring里的類。如不想引入過多依賴,可以自己仿照Executors.defaultThreadFactory()的代碼寫一個類更改namePrefix即可。
public static void main(String[] args){ CustomizableThreadFactory customizableThreadFactory = new CustomizableThreadFactory("mine-");//import org.springframework.scheduling.concurrent.CustomizableThreadFactory; ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS, new SynchronousQueue<>(), customizableThreadFactory, new ThreadPoolExecutor.CallerRunsPolicy()); for (int i = 0; i < 1; i++) { executor.execute(()->{ System.out.println(Thread.currentThread().getName()); }); } }
輸出:
mine-1
handler
handler – the handler to use when execution is blocked because the thread bounds and queue capacities are reached
達(dá)到線程邊界和隊(duì)列容量而阻止執(zhí)行時使用的處理程序
線程池的飽和策略,當(dāng)阻塞隊(duì)列滿了,且沒有空閑的工作線程,如果繼續(xù)提交任務(wù),必須采取一種策略處理該任務(wù),
線程池提供了4種策略:
AbortPolicy
: 直接拋出異常,默認(rèn)策略;
CallerRunsPolicy
: 用調(diào)用者所在的線程來執(zhí)行任務(wù);
DiscardOldestPolicy
: 丟棄阻塞隊(duì)列中靠最前的任務(wù),并執(zhí)行當(dāng)前任務(wù);
DiscardPolicy
: 直接丟棄任務(wù);
案例:
以 CallerRunsPolicy為案例。核心和最大線程數(shù)為1。
public static void main(String[] args) throws InterruptedException { ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS, new SynchronousQueue<>(), Executors.defaultThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy()); for (int i = 0; i < 3; i++) { executor.execute(()->{ System.out.println(Thread.currentThread().getName()); }); } }
輸出:
main
main
pool-1-thread-1
關(guān)閉線程池的方式
shutdown:
- 修改線程池狀態(tài)為SHUTDOWN
- 不再接收新提交的任務(wù)
- 中斷線程池中空閑的線程
- 第3步只是中斷了空閑的線程,但正在執(zhí)行的任務(wù)以及線程池任務(wù)隊(duì)列中的任務(wù)會繼續(xù)執(zhí)行完畢
shutdownNow:
- 修改線程池狀態(tài)為
STOP
- 不再接收任務(wù)提交
- 嘗試中斷線程池中所有的線程(包括正在執(zhí)行的線程)
- 返回正在等待執(zhí)行的任務(wù)列表
List<Runnable>
為什么不推薦使用Executors去創(chuàng)建線程池
newFixedThreadPool和newSingleThreadExecutor: 阻塞隊(duì)列為無界隊(duì)列,主要問題是堆積的請求處理隊(duì)列可能會耗費(fèi)非常大的內(nèi)存,甚至OOM。newCachedThreadPool和newScheduledThreadPool: 線程數(shù)最大數(shù)是Integer.MAX_VALUE,可能會創(chuàng)建數(shù)量非常多的線程,甚至OOM。
到此這篇關(guān)于Java ThreadPoolExecutor線程池有關(guān)介紹的文章就介紹到這了,更多相關(guān)Java ThreadPoolExecutor 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java 獲取服務(wù)器環(huán)境的實(shí)例詳解
這篇文章主要介紹了Java 獲取服務(wù)器環(huán)境的實(shí)例詳解的相關(guān)資料,這里提供實(shí)例和輸出結(jié)果,希望能幫助大家理解,需要的朋友可以參考下2017-07-07詳解Spring Cloud Config采用Git存儲時兩種常用的配置策略
這篇文章主要介紹了詳解Spring Cloud Config采用Git存儲時兩種常用的配置策略,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-07-07java 根據(jù)身份證號碼判斷出生日期、性別、年齡的示例
這篇文章主要介紹了java 根據(jù)身份證號碼判斷出生日期、性別、年齡的示例,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下2020-10-10