線程池復(fù)用原理

偽代碼

    
    static List<Runnable>  rList =new ArrayList<>();//用來保存task的隊列
    public static void main(String[] args) throws Exception {
         
        for( int  a=0;a<10;a++) {
            rList.add(new Test().new Run(a));
        }
        Thread thread   =new Thread(new Test().new  MyRun()); //創(chuàng)建線程溉委,線程池當(dāng)中是進行了一次封裝將 有個worker 類漓拾,該類實現(xiàn)了Runnable 接口,同時持有Thread 對象逼裆,在內(nèi)部實例化Thread 的時候,將自身當(dāng)做Runnable 傳給了內(nèi)部的Thread 對象,后續(xù)的工作就是在這個類的run()中進行了
        thread.start();;
    }

 
    class MyRun implements Runnable{  //thread 傳入的Runnable 
        @Override
        public void run() {// 當(dāng)thread.start() 后這個run()就會得到執(zhí)行出革,在這個方法的內(nèi)部循環(huán)task隊列叠萍,直接調(diào)用task 的run()
            // TODO Auto-generated method stub
            for(int i=0;i<rList.size();i++) {
                rList.get(i).run();
            }
            
        }
    }
    
    class Run implements Runnable{//相當(dāng)于我們自己傳入 的runnable 
        private int  i ;
        
        
        public Run(int i) {
            super();
            this.i = i;
        }


        @Override
        public void run() {
            // TODO Auto-generated method stub
          System.err.println(i);    
        }
    }
  public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
     
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {//小于核心線程數(shù)
            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);
    }

addWorker()

  private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;

            for (;;) {
                int wc = workerCountOf(c);
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                if (compareAndIncrementWorkerCount(c))
                    break retry;
                c = ctl.get();  // Re-read ctl
                if (runStateOf(c) != rs)
                    continue retry;
                // else CAS failed due to workerCount change; retry inner loop
            }
        }
      //創(chuàng)建新的線程
        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
            w = new Worker(firstTask); //實例化 Worker 類
            final Thread t = w.thread; //創(chuàng)建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());

                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        workers.add(w);
                        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;
    }

看下Worker 類芝发,worker 類本身是一個Runnable

  Worker(Runnable firstTask) {
            setState(-1); // inhibit interrupts until runWorker
            this.firstTask = firstTask;
            this.thread = getThreadFactory().newThread(this); // 這里創(chuàng)建了Thread ,并將this 傳入,上面說過苛谷,Worker 本身就是一個Runnable 對象
        }
 //既然是一個Runnable 辅鲸,必然復(fù)寫了run()
 public void run() {
            runWorker(this);
        }

    final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
            while (task != null || (task = getTask()) != null) {// 這里會阻塞,不停的循環(huán)任務(wù)隊列
                w.lock();
                // If pool is stopping, ensure thread is interrupted;
                // if not, ensure thread is not interrupted.  This
                // requires a recheck in second case to deal with
                // shutdownNow race while clearing interrupt
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    wt.interrupt();
                try {
                    beforeExecute(wt, task);
                    Throwable thrown = null;
                    try {
                        task.run();//執(zhí)行task 隊列中每個隊列的run()
                    } catch (RuntimeException x) {
                        thrown = x; throw x;
                    } catch (Error x) {
                        thrown = x; throw x;
                    } catch (Throwable x) {
                        thrown = x; throw new Error(x);
                    } finally {
                        afterExecute(task, thrown);
                    }
                } finally {
                    task = null;
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            processWorkerExit(w, completedAbruptly);
        }
    }

getTask()

// 為分析而簡化后的代碼
private Runnable getTask() {
    boolean timedOut = false;
    for (;;) {
        int c = ctl.get();
        int wc = workerCountOf(c);

        // timed變量用于判斷是否需要進行超時控制腹殿。
        // allowCoreThreadTimeOut默認(rèn)是false独悴,也就是核心線程不允許進行超時例书;
        // wc > corePoolSize,表示當(dāng)前線程池中的線程數(shù)量大于核心線程數(shù)量刻炒;
        // 對于超過核心線程數(shù)量的這些線程决采,需要進行超時控制
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

        if (timed && timedOut) {
            // 如果需要進行超時控制,且上次從緩存隊列中獲取任務(wù)時發(fā)生了超時坟奥,那么嘗試將workerCount減1,即當(dāng)前活動線程數(shù)減1树瞭,
            // 如果減1成功,則返回null筏勒,這就意味著runWorker()方法中的while循環(huán)會被退出移迫,其對應(yīng)的線程就要銷毀了,也就是線 
  程池中少了一個線程了
            if (compareAndDecrementWorkerCount(c))
                return null;
            continue;
        }

        try {
            Runnable r = timed ?
                workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                workQueue.take();

            // 注意workQueue中的poll()方法與take()方法的區(qū)別
            //poll方式取任務(wù)的特點是從緩存隊列中取任務(wù),最長等待keepAliveTime的時長管行,取不到返回null(當(dāng)timed 為true的時候厨埋,就說明當(dāng)前線程數(shù)大于核心線程數(shù),這個時候需要考慮是否需要銷毀線程捐顷,等keepAliveTime時間后如果返回null就表明需要銷毀該線程了)
            //take方式取任務(wù)的特點是從緩存隊列中取任務(wù)荡陷,若隊列為空,則進入阻塞狀態(tài),直到能取出對象為止(線程池中的線程數(shù)小于核心線程數(shù)迅涮,說明很閑废赞,只需要獲取任務(wù)即可)

            if (r != null)
                return r;
            timedOut = true;
        } catch (InterruptedException retry) {
            timedOut = false;
        }
    }
}

總結(jié):Thread.start() 會執(zhí)行傳入Runnable 的run(),同時執(zhí)行完后,當(dāng)前THread 就結(jié)束了叮姑,這怎么實現(xiàn)復(fù)用呢唉地?多線可能會有多個Runnable 啊,每次執(zhí)行完就結(jié)束了那豈不是每一個Runnable 都要重新new Thread(runable),這跟自己new Thread 有什么區(qū)別传透?其實線程池創(chuàng)建的Thead 傳入的Runnable 并不是我們傳入的task Runanble, 而是其內(nèi)部一個封裝的一個Worker 類耘沼,我們創(chuàng)建的Runnable 并沒有被當(dāng)做參數(shù)傳入到Runnable 中,而是被加入到對比當(dāng)中朱盐,在worker 這個runnable 的run()中去循環(huán)取出群嗤,就是讓worker的run()內(nèi)部執(zhí)行while循環(huán)(循環(huán)任務(wù)隊列,這樣就能保證一直復(fù)用了)兵琳,具體分 poll(),和take()兩種形式狂秘,來區(qū)分該線程是否需要被銷毀,同時也說明核心線程的其實就是最后活下來的那幾個線程

參考:https://blog.csdn.net/MingHuang2017/article/details/79571529

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末躯肌,一起剝皮案震驚了整個濱河市者春,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌清女,老刑警劉巖碧查,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡忠售,警方通過查閱死者的電腦和手機传惠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來稻扬,“玉大人卦方,你說我怎么就攤上這事√┘眩” “怎么了盼砍?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長逝她。 經(jīng)常有香客問我浇坐,道長,這世上最難降的妖魔是什么黔宛? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任近刘,我火速辦了婚禮,結(jié)果婚禮上臀晃,老公的妹妹穿的比我還像新娘觉渴。我一直安慰自己,他們只是感情好徽惋,可當(dāng)我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布案淋。 她就那樣靜靜地躺著,像睡著了一般险绘。 火紅的嫁衣襯著肌膚如雪踢京。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天宦棺,我揣著相機與錄音漱挚,去河邊找鬼。 笑死渺氧,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蹬屹。 我是一名探鬼主播侣背,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼慨默!你這毒婦竟也來了贩耐?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤厦取,失蹤者是張志新(化名)和其女友劉穎潮太,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡铡买,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年更鲁,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片奇钞。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡澡为,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出景埃,到底是詐尸還是另有隱情媒至,我是刑警寧澤,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布谷徙,位于F島的核電站拒啰,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏完慧。R本人自食惡果不足惜谋旦,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望骗随。 院中可真熱鬧蛤织,春花似錦、人聲如沸鸿染。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽涨椒。三九已至摊鸡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蚕冬,已是汗流浹背免猾。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留囤热,地道東北人猎提。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像旁蔼,于是被迫代替她去往敵國和親锨苏。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,619評論 2 354