JDK中線程池參數詳細解析

 

在jdk中爲咱們提供了三種建立線程池的方式,可是在阿里的編碼規範裏面都是明確禁止使用這三種api去建立線程池,推薦咱們去自定義線程池。爲何?api

 

要回答爲何,咱們須要明白建立線程池時,各參數的做用:緩存

首先咱們來看一下jdk提供的建立線程池的三個api:編碼

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

 

 

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

 

 3. newCachedThreadPool 建立一個帶有緩存的線程池日誌

 

 

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

 

那咱們來看一下ThreadPoolExecutor 建立線程池時須要的參數,以及其做用。blog

 

建立一個線程池,須要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.

 

這就是爲何咱們在使用線程池時必定要自定義線程池的緣由了。

相關文章
相關標籤/搜索