多線程(二)源碼分析1,線程和任務的創建

在上一節線程池使用中總結了線程池的一些常用的構造和基本的使用,其中也有大部分知識點,比如Java提供的四個基本的線程池配置,線程的特性,volatile, synchronized等關鍵字並沒有提到。整個Java多線程的使用需要學習的東西真的很多,懶人博主不想寫博客.jpg。

多線程的簡單實現相信大部分人在讀懂線程池的構造,明白部分設計模式後都可以手寫出來,但是本着對於源碼懷着敬畏之心的想法,還是需要學習一下源碼,明白大佬的編程思想,切勿閉門造車。

寫博客的初心僅僅是爲了見證和監督自己學習,並且在寫完博客之後,以後面試時就不會遇到:這個知識點我知道,但是我說不出的尷尬情景。如果有什麼地方寫的不對,歡迎大佬指正。

 

首先從execute()方法開始,逐步分析源碼。

一、execute(Runnable)

首先先看一下整個方法執行過程中使用的參數。

線程池通過一個整數包裝類對象來存儲當前線程的狀態(線程池的狀態+線程池的線程數),int一共32位二進制數,前三位保存的是狀態碼,後29位保存的是線程數,因此,線程池在構建時,哪怕線程池的最大線程數設置成Integer.MAX_VALUE,線程池實際最大線程也只能達到2^29次方-1。

這幾個參數主要是使用了大量的位運算,爲了方便觀看,我在註釋後寫了對應的二進制數值

1.關聯成員

    //ctl的成員變量value是int類型,前三位記錄的是線程池的狀態,後29位記錄的是當前的線程數,
    //由此可知,線程池最大也只能打開2^29次冪-1個線程
    
    //111+29個0,表示狀態RUNNING,線程數0
    private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
    
    //用於位運算,無含義
    private static final int COUNT_BITS = Integer.SIZE - 3;//29

    //用於位運算,其值等於29個1的二進制數,通過與該數進行與或操作,就可以獲取ctl的狀態碼和線程數
    private static final int CAPACITY = (1 << COUNT_BITS) - 1;//29個1

    //(這一行是官方註釋) runState is stored in the high-order bits
    //RUNNING,SHUTDOWN,STOP,TIDYING,TERMINATED表示線程池的狀態
    private static final int RUNNING = -1 << COUNT_BITS;    //111+29個0
    private static final int SHUTDOWN = 0 << COUNT_BITS;    //000+29個0
    private static final int STOP = 1 << COUNT_BITS;    //001+29個0
    private static final int TIDYING = 2 << COUNT_BITS;    //010+29個0
    private static final int TERMINATED = 3 << COUNT_BITS;    //011+29個0

 

 

2.關聯方法

接着看一下進行位運算的一些靜態方法

這些方法的參數c一般都是上面的ctl成員變量的值

    //通過與運算獲取狀態碼,也就是將後29位置0
    private static int runStateOf(int c) {
        return c & ~CAPACITY;
    }
    
    //通過與運算獲取當前線程數,也就是前三位數置0
    private static int workerCountOf(int c) {
        return c & CAPACITY;
    }

    //通過或運算,將狀態碼和線程數合併成一個數字。
    private static int ctlOf(int rs, int wc) {
        return rs | wc;
    }
    
    //如果狀態碼小於SHUTDOWN,返回TRUE,否則返回FALSE
    //因爲狀態碼僅有RUNNING是小於SHUTDOWN的。
    //所以當前狀態碼僅有爲RUNNING時,才返回TRUE,否則返回FALSE
    private static boolean isRunning(int c) {
        return c < SHUTDOWN;
    }

 

3.execute()

然後就是execute()中的代碼了

代碼較長,整體的流程差不多就是:

if  核心線程還未達到最大值   --》創建一個新的核心線程運行任務

否則--》嘗試將線程插入等待隊列--》插入後再次檢查線程的狀態,如果爲關閉狀態就移除這個任務,執行拒絕策略

如果插入失敗--》將該線程交給非核心線程運行

如果提交失敗--》執行拒絕策略

盜用別人的一張圖,大概就是這個樣子:

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        
        //c=線程池狀態,初始狀態是111+29個0
        int c = ctl.get();
        
        //如果當前的線程數小於核心線程數
        if (workerCountOf(c) < corePoolSize) {
            //如果將任務交給核心線程運行提交成功,返回調用該方法處
            if (addWorker(command, true))
                return;
            
            //添加失敗,重新獲取當前線程的狀態
            c = ctl.get();
        }

        //如果線程狀態爲RUNNING  &&  將該任務插入等待隊列成功
        if (isRunning(c) && workQueue.offer(command)) {
            //再次檢查當前線程狀態
            int recheck = ctl.get();
            //如果當前線程處於非運行狀態   &&   從等待隊列移除該任務成功
            if (! isRunning(recheck) && remove(command))
                //調用拒絕策略處理器處理拒絕這個任務請求
                reject(command);
            //否則,如果當前線程池的線程數==0
            else if (workerCountOf(recheck) == 0)
                //創建一個新的線程,任務爲null
                addWorker(null, false);
        }
    
        //如果將任務交給非核心線程去運行,提交失敗了
        else if (!addWorker(command, false))
            //執行拒絕策略
            reject(command);
    }

 

 

二、addWorker(Runable,boolean)

看完了execute()的流程和代碼,現在來看下線程池是如何提交任務並且創建線程的吧。

(看完之後哇的一聲吐出來)

1.關聯成員

private volatile ThreadFactory threadFactory;

//可重入鎖
private final ReentrantLock mainLock = new ReentrantLock();

//線程+任務的封裝對象的集合
private final HashSet<Worker> workers = new HashSet<Worker>();

 

2.關聯內部類

private final class Worker
        extends AbstractQueuedSynchronizer
        implements Runnable
    {
   
        private static final long serialVersionUID = 6138294804551838833L;

        /** Thread this worker is running in.  Null if factory fails. */
        //這個是內部類成員變量firstTask運行時所依賴的線程,如果工廠掛了,那麼這個線程爲null
        final Thread thread;

        /** Initial task to run.  Possibly null. */
        //初始運行的任務,有可能爲空
        Runnable firstTask;

        /** Per-thread task counter */
        volatile long completedTasks;

        /**
         * Creates with given first task and thread from ThreadFactory.
         * @param firstTask the first task (null if none)
         */
        Worker(Runnable firstTask) {
            setState(-1); // inhibit interrupts until runWorker
            this.firstTask = firstTask;
            //通過外部的方法獲取工廠,並且創建一個新的線程
            this.thread = getThreadFactory().newThread(this);
        }

        /** Delegates main run loop to outer runWorker  */
        //調用外部的run方法,這裏沒什麼好說的。
        public void run() {
            runWorker(this);
        }

        // Lock methods
        //
        // The value 0 represents the unlocked state.
        // The value 1 represents the locked state.

        protected boolean isHeldExclusively() {
            return getState() != 0;
        }

        protected boolean tryAcquire(int unused) {
            if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        protected boolean tryRelease(int unused) {
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }

        public void lock()        { acquire(1); }
        public boolean tryLock()  { return tryAcquire(1); }
        public void unlock()      { release(1); }
        public boolean isLocked() { return isHeldExclusively(); }

        void interruptIfStarted() {
            Thread t;
            if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
                try {
                    t.interrupt();
                } catch (SecurityException ignore) {
                }
            }
        }
    }

 

 

3.addWorker(Runnable,boolean)核心

private boolean addWorker(Runnable firstTask, boolean core) {
        //retry標記循環,之後循環體的代碼中遇到retry會直接回到該處
        retry:
        for (;;) {
            //獲取線程池當前的狀態
            int c = ctl.get();
            //獲取線程池當前的運行狀態
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            //如果線程池不處於RUNNING狀態,繼續判斷
            //如果也不是SHUTDOWN狀態,或者提交的任務不爲空,或者等待隊列是空的
            //滿足上述條件直接返回false
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;


            for (;;) {
                //獲取當前的線程數
                int wc = workerCountOf(c);
                //如果當前線程數已經達到了2^29次冪
                //或者當前線程數大於核心線程數|最大線程數(根據形參core而定)
                //滿足上述條件直接返回false
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                
                //該方法的作用是,如果當前線程池的線程數==c,則將當前線程池的線程數+1,並且返回true
                //由於多線程的原因所以可能會發生添加失敗的情況。
                if (compareAndIncrementWorkerCount(c))
                    //跳出標記的循環,也就是跳出整個外循環。
                    break retry;

                //重新獲取當前線程池狀態
                c = ctl.get();  // Re-read ctl
                //如果此時線程池的狀態和剛剛獲取的狀態不一樣
                if (runStateOf(c) != rs)
                    //1234,再來一次,從外循環處繼續再來一遍
                    continue retry;
                // else CAS failed due to workerCount change; retry inner loop
            }
        }

        //程序運行到這裏,線程池的線程數也就+1成功了,但是僅僅是數字+1,實際上線程還沒有創建
        //下面是創建線程的代碼。
        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
            w = new Worker(firstTask);
            final Thread t = w.thread;
            if (t != null) {
                
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {
                    // Recheck while holding lock.
                    // Back out on ThreadFactory failure or if
                    // shut down before lock acquired.
                    int rs = runStateOf(ctl.get());
                
                    //如果線程池是RUNNING狀態||(線程池處於即將關閉狀態&&任務爲null)
                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        //如果這個線程已經開始了,則拋出異常
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        //將Worker這個封裝對象添加到workers這個HashSet集合中
                        workers.add(w);

                        //更新largestPoolSize的值
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        //執行到此處,說明工作已經添加成功了
                        workerAdded = true;
                    }
                } finally {
                    //釋放鎖
                    mainLock.unlock();
                }
                //如果工作添加成功,那麼嘗試啓動該線程
                if (workerAdded) {
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            //如果工作啓動失敗了,那麼需要對工作隊列進行回滾,也就是移除該任務,檢查異常,防止線程池撲街。
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }

 

 

 

 

 

 

 

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