java執行緒池(ThreadPoolExecutor)原始碼解析一
阿新 • • 發佈:2019-02-20
執行緒池使用如下
public static void main(String[] args) {
int coreSize = 1;//核心執行緒數
int maxSize = 2;//最大執行緒數
long keepAliveTime = 10;//臨時執行緒空閒時間
TimeUnit unit = TimeUnit.MINUTES;//臨時執行緒空閒時間單位
BlockingQueue<Runnable> blockQueue = new LinkedBlockingQueue<Runnable>();//用於存任務的阻塞佇列
RejectedExecutionHandler handler = new RejectedExecutionHandler() {//任務佇列滿了以後對不能入隊的任務的處理策略
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.out.println("執行緒池已滿");
}
};
ThreadPoolExecutor executor = new ThreadPoolExecutor(coreSize, maxSize, keepAliveTime, unit, blockQueue,
handler);
for (int i = 0; i < 10; i++) {
executor.execute(new Runnable() {
public void run() {
System.out.println(Thread.currentThread());
}
});
}
executor.shutdown();
}
excecute()方法
可以看出核心方法是execute() 方法,下面是加了註釋的execute()方法
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
*
* 1. 如果執行緒數小於核心執行緒數,則啟動一個新的執行緒,並將傳入的runable作為他的第一個任務。
* addWorker()方法自動檢查執行緒池執行狀態和工作執行緒數,如果當前狀態不應該再啟動新的執行緒,
* addwoker()返回false
*
* 2. 如果一個task成功進入佇列,還是要再檢查一次是否需要建立一個新的執行緒(因為在上一次檢查後,
* 之前存活的執行緒的生命週期可能已經結束了),或者進入這個方法之後執行緒池被關閉了。因此重新檢查狀態,
* 根據情況來決定是移除任務還是再建立一個執行緒
*
* 3. 如果不能將任務放入佇列,就嘗試再啟動一個新的執行緒。如果失敗了,那就說明執行緒池關閉了或者執行緒池滿了,
* 所以後面執行拒絕策略
*/
int c = ctl.get(); //ctl 是一個 AtomicInteger,用來存執行緒池的狀態和工作執行緒數量,以後會說明
if (workerCountOf(c) < corePoolSize) { //workerCountOf(c) 方法獲取執行緒池已有執行緒數量
if (addWorker(command, true)) //addWoker方法嘗試建立新的執行緒執行任務
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
/*下面又進行了一次檢查,主要是防止這種情況:執行緒A執行完上面的isRunning,返回執行中,然後掛起。
* 這時候執行緒B呼叫了shutdown,關閉了執行緒池,這時候如果成功將執行緒池內所有執行緒結束了,這是執行緒A繼續執行
* workQueue.offer(command) 將任務入隊,如果沒有下面的第二次檢查,這個任務將漏掉,既沒有執行run方法,
* 也沒有執行拒絕策略
*/
if (! isRunning(recheck) && remove(command))//isRunning(recheck) 返回當前執行緒的狀態是否是執行中
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command); //reject方法很簡單就是呼叫了傳入的 rejectExcetpionHandler
}
reject(command)方法
/**
* Invokes the rejected execution handler for the given command.
* Package-protected for use by ScheduledThreadPoolExecutor.
*/
final void reject(Runnable command) {
handler.rejectedExecution(command, this);
}