線程池6th卷:大展經綸補天手

聊一聊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 的生命週期狀態的含義:

  1. RUNNING:正常營業:接受新的任務並且處理隊列中的任務( Accept new tasks and process queued tasks)
  2. SHUTDOWN:打烊狀態:不再接受新任務,但是處理隊列中的任務( Don’t accept new tasks, but process queued tasks)
  3. STOP:停業狀態:所有任務全部暫停,且嘗試打斷正在執行的任務( Don’t accept new tasks, don’t process queued tasks,and interrupt in-progress tasks)
  4. TIDYING:清算狀態:所有任務全部暫停,辭退全部廚師,調用hook方法進入破產流程(All tasks have terminated, workerCount is zero, the thread transitioning to state TIDYING will run the terminated() hook method)
  5. 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的代碼邏輯以及註釋都是非常好的…

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章