執行緒池的作業原理
ThreadPoolExecutor(int corePoolSize,// 核心執行緒數
int maximumPoolSize,//最大執行緒數
long keepAliveTime,//空閑執行緒存活時間
TimeUnit unit,//存活時間單位
BlockingQueue<Runnable> workQueue,//阻塞佇列
RejectedExecutionHandler handler)//拒絕策略
當ThreadPoolExecutor執行緒池被創建的時候,里邊是沒有作業執行緒的,直到有任務進來(執行了execute方法)才開始創建執行緒去作業,作業原理如下(即execute方法運行原理):
呼叫執行緒池的execute方法的時候如果當前的作業執行緒數 小于 核心執行緒數,則創建新的執行緒執行任務;否則將任務加入阻塞佇列,如果佇列滿了則根據最大執行緒數去創建額外(核心執行緒數以外)的作業執行緒去執行任務;如果作業執行緒數達到了最大執行緒數,則根據拒絕策略去執行,存活時間到期的話只是回收核心執行緒(maximumPoolSize - corePoolSize)以外的執行緒
// 分3個步驟進行:
// 1. 如果運行的執行緒少于corePoolSize,請嘗試使用給定的命令作為第一個執行緒啟動一個新執行緒的任務,對addWorker的呼叫會自動檢查runState和workerCount,這樣可以防止虛假警報的增加當它不應該的時候,回傳false,
// 2. 如果任務可以成功排隊,那么我們仍然需要來再次檢查我們是否應該添加執行緒(因為自從上次檢查后,現有的已經死了)或者那樣自進入此方法后池就關閉了,所以我們重新檢查狀態,并在必要時回滾佇列停止,或啟動一個新執行緒(如果沒有執行緒),
// 3.如果我們不能將任務放入佇列,那么我們嘗試添加一個新的執行緒,如果它失敗了,我們知道我們被關倍訓飽和了所以拒絕這個任務,
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
// 第一步
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
// 第二步驟
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
// 第三步
else if (!addWorker(command, false))
reject(command);
}
五種執行緒池
ExecutorService threadPool = null;
threadPool = Executors.newCachedThreadPool();
//有緩沖的執行緒池,執行緒數 JVM 控制
threadPool = Executors.newFixedThreadPool(3);
//固定大小的執行緒池
threadPool = Executors.newScheduledThreadPool(2);
threadPool = Executors.newSingleThreadExecutor();
//單執行緒的執行緒池,只有一個執行緒在作業
threadPool = new ThreadPoolExecutor();
//默認執行緒池,可控制引數比較多
ThreadPoolExecutor引數:
public class ThreadPoolExecutor extends AbstractExecutorService {
.....
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue);
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory);
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler);
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler);
...
}
引數含義以及功能:
corePoolSize:核心池的大小,這個引數跟后面講述的執行緒池的實作原理有非常大的關系,在創建了執行緒池后,默認情況下,執行緒池中并沒有任何執行緒,而是等待有任務到來才創建執行緒去執行任務,除非呼叫了prestartAllCoreThreads()或者prestartCoreThread()方法,從這2個方法的名字就可以看出,是預創建執行緒的意思,即在沒有任務到來之前就創建corePoolSize個執行緒或者一個執行緒,默認情況下,在創建了執行緒池后,執行緒池中的執行緒數為0,當有任務來之后,就會創建一個執行緒去執行任務,當執行緒池中的執行緒數目達到corePoolSize后,就會把到達的任務放到快取佇列當中;maximumPoolSize:執行緒池最大執行緒數,這個引數也是一個非常重要的引數,它表示在執行緒池中最多能創建多少個執行緒;keepAliveTime:表示執行緒沒有任務執行時最多保持多久時間會終止,默認情況下,只有當執行緒池中的執行緒數大于corePoolSize時,keepAliveTime才會起作用,直到執行緒池中的執行緒數不大于corePoolSize,即當執行緒池中的執行緒數大于corePoolSize時,如果一個執行緒空閑的時間達到keepAliveTime,則會終止,直到執行緒池中的執行緒數不超過corePoolSize,但是如果呼叫了allowCoreThreadTimeOut(boolean)方法,在執行緒池中的執行緒數不大于corePoolSize時,keepAliveTime引數也會起作用,直到執行緒池中的執行緒數為0;unit:引數keepAliveTime的時間單位,有7種取值,在TimeUnit類中有7種靜態屬性:
TimeUnit.DAYS; //天
TimeUnit.HOURS; //小時
TimeUnit.MINUTES; //分鐘
TimeUnit.SECONDS; //秒
TimeUnit.MILLISECONDS; //毫秒
TimeUnit.MICROSECONDS; //微妙
TimeUnit.NANOSECONDS; //納秒
workQueue:一個阻塞佇列,用來存盤等待執行的任務,這個引數的選擇也很重要,會對執行緒池的運行程序產生重大影響,一般來說,這里的阻塞佇列有以下幾種選擇:
ArrayBlockingQueue;
LinkedBlockingQueue;
SynchronousQueue;
ArrayBlockingQueue和PriorityBlockingQueue使用較少,一般使用LinkedBlockingQueue和Synchronous,執行緒池的排隊策略與BlockingQueue有關,
-
threadFactory:執行緒工廠,主要用來創建執行緒; -
handler:表示當拒絕處理任務時的策略,有以下四種取值: -
ThreadPoolExecutor.AbortPolicy:(默認)丟棄任務并拋出RejectedExecutionException例外,ThreadPoolExecutor.DiscardPolicy:也是丟棄任務,但是不拋出例外,ThreadPoolExecutor.DiscardOldestPolicy:丟棄佇列最前面的任務,然后重新嘗試執行任務(重復此程序)ThreadPoolExecutor.CallerRunsPolicy:由呼叫執行緒處理該任務
四種拒絕策略
RejectedExecutionHandler rejected = null;
rejected = new ThreadPoolExecutor.AbortPolicy();
//默認,佇列滿了丟任務拋出例外
rejected = new ThreadPoolExecutor.DiscardPolicy();
//佇列滿了丟任務不拋例外
rejected = new ThreadPoolExecutor.DiscardOldestPolicy();
//將最早進入佇列的任務刪,之后再嘗試加入佇列
rejected = new ThreadPoolExecutor.CallerRunsPolicy();
//如果添加到執行緒池失敗,那么主執行緒會自己去執行該任務;如果執行程式已關閉(主執行緒運行結束),則會丟棄該任務
當然也可以根據應用場景實作 RejectedExecutionHandler 介面,自定義飽和策略,如記錄 日志或持久化存盤不能處理的任務
三種阻塞佇列
BlockingQueue<Runnable> workQueue = null;
workQueue = new ArrayBlockingQueue<>(5);
//基于陣列的先進先出佇列,有界
workQueue = new LinkedBlockingQueue<>();
//基于鏈表的先進先出佇列,無界
workQueue = new SynchronousQueue<>();
//無緩沖的等待佇列,無界
來源:blog.csdn.net/AIGUO666666/article/details/103251145
近期熱文推薦:
1.1,000+ 道 Java面試題及答案整理(2021最新版)
2.別在再滿屏的 if/ else 了,試試策略模式,真香!!
3.臥槽!Java 中的 xx ≠ null 是什么新語法?
4.Spring Boot 2.5 重磅發布,黑暗模式太炸了!
5.《Java開發手冊(嵩山版)》最新發布,速速下載!
覺得不錯,別忘了隨手點贊+轉發哦!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/303721.html
標籤:其他
