大家好,我是小黑,一個在互聯網茍且偷生的農民工,
池化
執行緒池是在計算機開發中常見的一種池化技術,是為了提高資源的利用率,將一些資源重復利用,避免重復的構建來提高效率,類似字串常量池,資料庫連接池,HttpClient連接池等,都是用的池化技術,
執行緒池
在沒有執行緒池概念之前,我們要使用執行緒必須先通過創建一個Thread類來完成執行緒的構建,并呼叫start()方法開啟,在執行緒執行完會將執行緒銷毀,而執行緒資源是很寶貴的,創建和銷毀執行緒會造成資源的浪費,而執行緒池是將創建的執行緒存盤到一個池中,在需要使用時從池中去拿,使用完之后再講執行緒歸還到池中,下一次接著使用,
舉個栗子,好比我們去銀行辦理業務時,銀行會有視窗為客戶辦理業務,如果沒有執行緒池,就好比每次來一個客戶,銀行都打開一個視窗,辦理完業務之后將視窗關閉,這樣確實很浪費時間,所以銀行會默認開幾個視窗,比如三個,等客戶來辦理業務;一個客戶辦理完,下一個客戶可以繼續在這個視窗辦理,

核心執行緒數
在執行緒池初始化時,會指定創建核心執行緒的數量,有任務提交給執行緒池時,先判斷是否有空閑執行緒,如果有空閑執行緒,則直接使用,如果沒有則看當前執行緒池中的數量是不是小于核心執行緒數,如果是則創建新的執行緒,如果已經到達核心執行緒數,則需要做下一步操作,
等待佇列
下一步操作就是要進入等待佇列,等待佇列好比是去銀行辦業務時沒有空閑視窗,需要坐在大廳的座椅上排隊;執行緒池也是一樣,如果沒有核心執行緒,則需要將任務放入等待佇列,等待有空閑執行緒再執行,
最大執行緒數
那我們都知道銀行有時候人特別多的時候,會增加視窗,一般是當大廳的座椅坐滿人時,視窗都很緊張處理不過來,這是會增加視窗;執行緒池也是一樣,如果等待的任務已經放滿了等待佇列,并且核心執行緒都在繁忙,這時會查看執行緒池中的執行緒數量是否到達最大執行緒數,如果沒有則會創建新的執行緒來繼續處理,

拒絕策略
那如果說,執行緒池中的執行緒已經到達最大執行緒數并且都在繁忙,還有新的任務進來,好比銀行已經坐滿人了,視窗也都在忙,客戶都排到門口了,這時要是還有人要辦理,應該怎么處理呢?銀行一般會讓這個人先回家,改天再來辦,或者如果是個大客戶,銀行可能會單獨帶去VIP辦公室辦理等等,執行緒池在這種情況下也有相應的處理方式,這種處理方式我們稱之為拒絕策略,如果會放任務在當前執行緒執行,或者直接將任務丟棄等等,在后面的章節中我會詳細給大家介紹,
JDK中的執行緒池
在JDK中提供了相應的API來創建執行緒池,這些API也是在我們最近講到過的JUC包中,

Executor
首先,執行緒池需要具備能夠執行任務的能力,這個任務通過一個執行緒來處理,而這個執行任務的能力通過Executor介面來約定,
public interface Executor {
void execute(Runnable command);
}
ExecutorService
在某些場景我們需要知道任務執行完之后的結果,拿到回傳值,而Runnable介面是沒有回傳值的;以及一些可以關閉執行緒池中的執行緒,執行執行緒中的任務的方法,定義在ExecutorService介面中,

ThreadPoolExecutor
ThreaPoolExecutor則是對ExecutorService的具體實作類,通過ThreaPoolExecutor類可以創建出一個執行緒池,我們先來看一下代碼,
ThreadPoolExecutor executor = new ThreadPoolExecutor(
// 核心執行緒數 corePoolSize
3,
// 最大執行緒數 maximumPoolSize
5,
// 空閑執行緒保留存活的時間和時間單位
10, TimeUnit.SECONDS,
// 等待佇列
new ArrayBlockingQueue<>(3),
// 創建執行緒的工廠
Executors.defaultThreadFactory(),
// 拒絕策略
new ThreadPoolExecutor.AbortPolicy()
);
從代碼我們可以看出,創建一個執行緒池,需要指定我們上面說到的核心執行緒數,最大執行緒數,等待佇列,拒絕策略等,并且還要指定創建執行緒的工廠物件,
當然ThreadPoolExecutor也有其他的構造方法,可以不顯式指定拒絕策略和工廠物件,
new ThreadPoolExecutor(3,5,10,TimeUnit.SECONDS,new ArrayBlockingQueue<>(3));
// 構造方法
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
// 使用默認的執行緒工廠和默認的拒絕策略,
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
7個執行緒池引數
- corePoolSize:核心執行緒數
- maximumPoolSize:最大執行緒數
- keepAliveTime:空閑執行緒保持存活時間
- unit:空閑執行緒保持存活時間單位
- workQueue:等待佇列
- threadFactory:執行緒創建工廠
- RejectedExecutionHandler:拒絕策略
4種拒絕策略
這里我們說一下4中拒絕策略,介面RejectedExecutionHandler定義了拒絕策略,所有的拒絕策略都需要實作該介面,
public interface RejectedExecutionHandler {
void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}
在ThreadPoolExecutor類中定義了4個拒絕策略的具體實作,
- AbortPolicy:拒絕處理,拋出例外
- CallerRunsPolicy:由創建該執行緒的執行緒(main)執行
- DiscardPolicy: 丟棄,不拋出例外
- DiscardOldestPolicy:和最早創建的執行緒進行競爭,不拋出例外
可通過如下方式進行拒絕策略的創建,
// 拒絕處理,拋出例外
new ThreadPoolExecutor.AbortPolicy();
// 由創建該執行緒的執行緒(main)執行
new ThreadPoolExecutor.CallerRunsPolicy();
// 丟棄,不拋出例外
new ThreadPoolExecutor.DiscardPolicy();
// 和最早創建的執行緒進行競爭,不拋出例外
new ThreadPoolExecutor.DiscardOldestPolicy();
4種執行緒池種類
那么具體我們在使用時應該創建怎樣的執行緒池呢?在JDK的Executors工具類為我們提供了4種執行緒池的創建方式,
// 只有一個執行緒
Executors.newSingleThreadExecutor();
// 固定執行緒數
Executors.newFixedThreadPool(5);
// 可伸縮的
Executors.newCachedThreadPool();
// 可延遲執行,使用優先佇列DelayedWorkQueue
Executors.newScheduledThreadPool(3);
小結
好的,通過今天的內容我們先對執行緒池的使用有一個初步的了解,下期內容再跟大家深入決議一下執行緒池中的具體實作原理,
本期內容就到這里,我們下期見,
關注公眾號【小黑說Java】干貨不斷,

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/297263.html
標籤:其他
上一篇:Python爬蟲入門案例教學:批量爬取彼岸桌面4K超清美女壁紙
下一篇:設計模式---裝飾者模式
