聊一聊Doug Lea的生意經
1.第一階段:Executor
早期創業時候不想那麼多,能做生意就行。所以只有一個方法:execute()
public interface Executor {
void execute(Runnable command);
}
2.第二階段:ExecutorService
發展纔是硬道理,該嚴格要求一下自己。
public interface ExecutorService extends Executor {
void shutdown(); // 正常關門
List<Runnable> shutdownNow(); //土匪來了,立即關門
boolean isShutdown(); // 判斷是否關門
boolean isTerminated(); // 是否破產
boolean awaitTermination(long timeout, TimeUnit unit) // 等待破產
submit() // 服務一個客人
invokeAll() // 服務多個客人並且返回所有人的狀態和結果
invokeAny() // 服務多個客人,只返回吃完飯的人的評價
}
.
.
.
上面的部分足夠展開我們我們的話題,更爲詳細的可以參考: 線程池4th卷:大鵬展翅恨天低
線程池的狀態管理
人生無常,世事難料,做生意當然是有成功也有失敗…總公司爲了便於管理,當然需要實時掌握所創建的連鎖店的狀態(runState)。
Doug Lea的實現在ThreadPoolExecutor,現在我們結合源碼看一下線程池的狀態:
public class ThreadPoolExecutor extends AbstractExecutorService {
/**
*The main pool control state, ctl, is an atomic integer packing
* two conceptual fields:
* 線程池控制狀態:包含兩部分內容。
* workerCount(工作線程的數量):indicating the effective number of threads
* runState(線程池的狀態):indicating whether running, shutting down etc
*/
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
/**
* In order to pack them into one int, we limit workerCount to
* (2^29)-1 (about 500 million) threads rather than (2^31)-1 (2
* billion) otherwise representable.
* 爲了將其限制在一個Int的範圍內,限制廚師數量(workerCount)大約爲5億個
*/
private static final int COUNT_BITS = Integer.SIZE - 3;
// runState is stored in the high-order bits
private static final int RUNNING = -1 << COUNT_BITS;
private static final int SHUTDOWN = 0 << COUNT_BITS;
private static final int STOP = 1 << COUNT_BITS;
private static final int TIDYING = 2 << COUNT_BITS;
private static final int TERMINATED = 3 << COUNT_BITS;
}
1. 談一下runState 的生命週期狀態的含義:
- RUNNING:正常營業:接受新的任務並且處理隊列中的任務( Accept new tasks and process queued tasks)
- SHUTDOWN:打烊狀態:不再接受新任務,但是處理隊列中的任務( Don’t accept new tasks, but process queued tasks)
- STOP:停業狀態:所有任務全部暫停,且嘗試打斷正在執行的任務( Don’t accept new tasks, don’t process queued tasks,and interrupt in-progress tasks)
- TIDYING:清算狀態:所有任務全部暫停,辭退全部廚師,調用hook方法進入破產流程(All tasks have terminated, workerCount is zero, the thread transitioning to state TIDYING will run the terminated() hook method)
- TERMINATED:破產狀態:過眼雲煙…( terminated() has completed)
- (SHUTDOWN and pool and queue empty),處於SHUTDOWN狀態且線程池和任務隊列都爲空
- (STOP and pool empty),處於STOP狀態,線程池爲空
2. 開店(ThreadPoolExecutor)的生命歷程
世事真難料,人生信有涯
3.涉及runState的方法
多說一句,線程池這塊的源碼還是非常好看的,除了判斷語句不加{}讓人有點捉急…
3.1 execute()
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
// 第一步:判斷workerCount < corePoolSize,則addWorker
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
// 第二步:判斷線程池的狀態,且可以成功添加任務
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
// 由於上面不是原子操作,所以需要double check. 判斷不是RUNNING狀態且可從任務隊列中刪除此任務(具體可以參見remove()方法).執行拒絕策略。
if (! isRunning(recheck) && remove(command)){
reject(command);
}else if (workerCountOf(recheck) == 0)
addWorker(null, false);
//第三步: 若不能添加任務,則addWorker,若失敗就執行拒絕策略
}else if (!addWorker(command, false)){
reject(command);
}
}
這裏提一下remove()方法
public boolean remove(Runnable task) {
boolean removed = workQueue.remove(task);
// 重點是這裏的嘗試終止操作。
tryTerminate(); // In case SHUTDOWN and now empty
return removed;
}
3.2 shutdown()
代碼邏輯都很清晰,不多囉嗦…
public void shutdown() {
// 保證線程安全,使用可重入鎖(ReentrantLock),需要幫助的可以評論留言
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 1. 檢查權限
checkShutdownAccess();
// 2.將runState狀態置爲SHUTDOWN,
advanceRunState(SHUTDOWN);
// 3. 中斷所有**空閒線程(idle)**
interruptIdleWorkers();
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
// 嘗試終止線程池
tryTerminate();
}
3.3 shutdownNow()
注意對比和shutdown()的區別
public List<Runnable> shutdownNow() {
List<Runnable> tasks;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
advanceRunState(STOP);
// 打斷所有線程
interruptWorkers();
// 返回未執行的任務
tasks = drainQueue();
} finally {
mainLock.unlock();
}
// 嘗試終止線程池
tryTerminate();
return tasks;
}
3.4 awaitTermination()
public boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException {
long nanos = unit.toNanos(timeout);
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 這裏死循環輪詢 線程池的狀態 以及 判斷等待時間
for (;;) {
if (runStateAtLeast(ctl.get(), TERMINATED))
return true;
if (nanos <= 0)
return false;
nanos = termination.awaitNanos(nanos);
}
} finally {
mainLock.unlock();
}
}
線程池的狀態相關的東西大概就講到這裏,其實結合你開店做老闆的經驗,大概脈絡就很清晰啦…
這裏還是更推薦RTFSC… Doug Lea的代碼邏輯以及註釋都是非常好的…