JDK中線程池參數詳細解析


 

在jdk中為我們提供了三種創建線程池的方式,但是在阿里的編碼規范里面都是明確禁止使用這三種api去創建線程池,推薦我們去自定義線程池。為什么?

 

要回答為什么,我們需要明白創建線程池時,各參數的作用:

首先我們來看一下jdk提供的創建線程池的三個api:

1. newFixedThreadPool    創建固定數量線程的線程池。

 

 

2. newSingleThreadExecutor   創建單線程的線程池

 

 3. newCachedThreadPool 創建一個帶有緩存的線程池

 

 

發現這幾種創建線程池的api,實質上都是依賴於ThreadPoolExecutor類來創建線程池。

 

那我們來看一下ThreadPoolExecutor 創建線程池時需要的參數,以及其作用。

 

創建一個線程池,需要7個參數。

1. corePoolSize: 線程池的核心線程數量。初始是不創建線程的。當有任務提交到線程池時,判定如果已經創建的線程數量小於核心數量,且沒有空閑線程時,則會新建一個線程去執行新提交的任務。如果已經達到核心線程數量, 則會加入到阻塞隊列中。

2.maximumPoolSize: 線程池的最大容量。當線程池的阻塞隊列放滿了, 並且線程數量還未達到線程池的最大線程數量, 則會創建新的線程,直到達到最大值

3.keepAliveTime   當阻塞隊列里面的任務被執行完了, 且有空閑線程時,指定大於核心線程池數量的部分空閑線程的存活時間, 畢竟線程也是需要消耗資源的,及時回收很有必要。當線程空閑的時間超過這個時間后,會回收掉一部分空閑線程,使其線程池中的線程數量不大於核心線程的數量

 4.unit  和keepAliveTIme 配套使用,上面指定了時間的數值,但是沒有指定時間的單位(時,分,秒等), 這里需要指定時間的單位

5.workQueue  阻塞隊列,當沒有空閑線程時,多余的任務緩存的地方。

6.threadFactory 線程工廠,用來創建線程時,設定線程的一些參數。通常我們為了后續查看日志方便,可以通過這個來指定我們自定義的線程池的線程名稱

7.handler  當線程數量達到最大值時,且阻塞隊列慢了, 后續在提交任務時,沒有地方可以接受繼續的提交的任務。這種情況下的一個拒絕策略。

 

拒絕策略jdK,提供了四種:

// 由提交任務的線程執行任務
public
static class CallerRunsPolicy implements RejectedExecutionHandler { public CallerRunsPolicy() { } public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { r.run(); } } }
// 不在接收新的任務,直接拋出異常
public static class AbortPolicy implements RejectedExecutionHandler { public AbortPolicy() { } public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { throw new RejectedExecutionException("Task " + r.toString() + " rejected from " + e.toString()); } }
// 不接收也不拋出異常,空實現,忽略該任務
public static class DiscardPolicy implements RejectedExecutionHandler { public DiscardPolicy() { } public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { } } // 拋棄最老的任務,從阻塞隊列中移除最早提交的任務,然后將該任務加入。 public static class DiscardOldestPolicy implements RejectedExecutionHandler { public DiscardOldestPolicy() { } public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { e.getQueue().poll(); e.execute(r); } } }

 

 

講解完了創建線池時,各參數的作用,那么我們現在再反過來看為什么不讓使用jdk提供的apI來創建線程池,而是需要我們自定義線程池。

newFixedThreadPool ,newSingleThreadExecutor    這兩種api 使用的阻塞隊列都是無界隊列,也就是無論有多少個任務來,我們都接收。我們的內存是有限的,阻塞隊列里面存儲的任務是越多,也就意味着占用的內存越多,這樣會導致占用大量的內存,容易引起OOM

newCachedThreadPool  而這個api 的阻塞隊列容量為0,最大線程數量為Integer 的最大值。每當有一個任務提交時,阻塞隊列存儲不了,就會新開啟一個線程,當任務比較多,則會創建大量的線程, 引起OOM.

 

這就是為什么我們在使用線程池時一定要自定義線程池的原因了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM