<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    xylz,imxylz

    關(guān)注后端架構(gòu)、中間件、分布式和并發(fā)編程

       :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      111 隨筆 :: 10 文章 :: 2680 評論 :: 0 Trackbacks

     [本文地址:http://m.tkk7.com/Files/xylz/Inside.Java.Concurrency_33.ThreadPool.part6_ThreadFactory_Worker.pdf]


    線程池數(shù)據(jù)結(jié)構(gòu)與線程構(gòu)造方法

    由于已經(jīng)看到了ThreadPoolExecutor的源碼,因此很容易就看到了ThreadPoolExecutor線程池的數(shù)據(jù)結(jié)構(gòu)。圖1描述了這種數(shù)據(jù)結(jié)構(gòu)。

    ThreadPoolExecutor

    圖1 ThreadPoolExecutor 數(shù)據(jù)結(jié)構(gòu)

    其實,即使沒有上述圖形描述ThreadPoolExecutor的數(shù)據(jù)結(jié)構(gòu),我們根據(jù)線程池的要求也很能夠猜測出其數(shù)據(jù)結(jié)構(gòu)出來。

    • 線程池需要支持多個線程并發(fā)執(zhí)行,因此有一個線程集合Collection<Thread>來執(zhí)行線程任務(wù);
    • 涉及任務(wù)的異步執(zhí)行,因此需要有一個集合來緩存任務(wù)隊列Collection<Runnable>;
    • 很顯然在多個線程之間協(xié)調(diào)多個任務(wù),那么就需要一個線程安全的任務(wù)集合,同時還需要支持阻塞、超時操作,那么BlockingQueue是必不可少的;
    • 既然是線程池,出發(fā)點就是提高系統(tǒng)性能同時降低資源消耗,那么線程池的大小就有限制,因此需要有一個核心線程池大小(線程個數(shù))和一個最大線程池大小(線程個數(shù)),有一個計數(shù)用來描述當(dāng)前線程池大小;
    • 如果是有限的線程池大小,那么長時間不使用的線程資源就應(yīng)該銷毀掉,這樣就需要一個線程空閑時間的計數(shù)來描述線程何時被銷毀;
    • 前面描述過線程池也是有生命周期的,因此需要有一個狀態(tài)來描述線程池當(dāng)前的運行狀態(tài);
    • 線程池的任務(wù)隊列如果有邊界,那么就需要有一個任務(wù)拒絕策略來處理過多的任務(wù),同時在線程池的銷毀階段也需要有一個任務(wù)拒絕策略來處理新加入的任務(wù);
    • 上面種的線程池大小、線程空閑實際那、線程池運行狀態(tài)等等狀態(tài)改變都不是線程安全的,因此需要有一個全局的鎖(mainLock)來協(xié)調(diào)這些競爭資源;
    • 除了以上數(shù)據(jù)結(jié)構(gòu)以外,ThreadPoolExecutor還有一些狀態(tài)用來描述線程池的運行計數(shù),例如線程池運行的任務(wù)數(shù)、曾經(jīng)達到的最大線程數(shù),主要用于調(diào)試和性能分析。

     

    對于ThreadPoolExecutor而言,一個線程就是一個Worker對象,它與一個線程綁定,當(dāng)Worker執(zhí)行完畢就是線程執(zhí)行完畢,這個在后面詳細討論線程池中線程的運行方式。

    既然是線程池,那么就首先研究下線程的構(gòu)造方法。

    public interface ThreadFactory {
        Thread newThread(Runnable r);
    }

     

    ThreadPoolExecutor使用一個線程工廠來構(gòu)造線程。線程池都是提交一個任務(wù)Runnable,然后在某一個線程Thread中執(zhí)行,ThreadFactory 負責(zé)如何創(chuàng)建一個新線程。

    在J.U.C中有一個通用的線程工廠java.util.concurrent.Executors.DefaultThreadFactory,它的構(gòu)造方式如下:

    static class DefaultThreadFactory implements ThreadFactory {
       
    static final AtomicInteger poolNumber = new AtomicInteger(1);
       
    final ThreadGroup group;
       
    final AtomicInteger threadNumber = new AtomicInteger(1);
       
    final String namePrefix;
        DefaultThreadFactory() {
            SecurityManager s
    = System.getSecurityManager();
            group
    = (s != null)? s.getThreadGroup() :
                                 Thread.currentThread().getThreadGroup();
            namePrefix
    = "pool-" +
                          poolNumber.getAndIncrement()
    +
                        
    "-thread-";
        }
       
    public Thread newThread(Runnable r) {
            Thread t
    = new Thread(group, r,
                                  namePrefix
    + threadNumber.getAndIncrement(),
                                 
    0);
           
    if (t.isDaemon())
                t.setDaemon(
    false);
           
    if (t.getPriority() != Thread.NORM_PRIORITY)
                t.setPriority(Thread.NORM_PRIORITY);
           
    return t;
        }
    }

     

    在這個線程工廠中,同一個線程池的所有線程屬于同一個線程組,也就是創(chuàng)建線程池的那個線程組,同時線程池的名稱都是“pool-<poolNum>-thread-<threadNum>”,其中poolNum是線程池的數(shù)量序號,threadNum是此線程池中的線程數(shù)量序號。這樣如果使用jstack的話很容易就看到了系統(tǒng)中線程池的數(shù)量和線程池中線程的數(shù)量。另外對于線程池中的所有線程默認都轉(zhuǎn)換為非后臺線程,這樣主線程退出時不會直接退出JVM,而是等待線程池結(jié)束。還有一點就是默認將線程池中的所有線程都調(diào)為同一個級別,這樣在操作系統(tǒng)角度來看所有系統(tǒng)都是公平的,不會導(dǎo)致競爭堆積。

    線程池中線程生命周期

    一個線程Worker被構(gòu)造出來以后就開始處于運行狀態(tài)。以下是一個線程執(zhí)行的簡版邏輯。

    private final class Worker implements Runnable {
       
    private final ReentrantLock runLock = new ReentrantLock();
       
    private Runnable firstTask;
        Thread thread;
        Worker(Runnable firstTask) {
           
    this.firstTask = firstTask;
        }
       
    private void runTask(Runnable task) {
           
    final ReentrantLock runLock = this.runLock;
            runLock.lock();
           
    try {
               task.run();
            }
    finally {
                runLock.unlock();
            }
        }
       
    public void run() {
           
    try {
                Runnable task
    = firstTask;
                firstTask
    = null;
               
    while (task != null || (task = getTask()) != null) {
                    runTask(task);
                    task
    = null;
                }
            }
    finally {
                workerDone(
    this);
            }
        }
    }

     

    ThreadPoolExecutor-Worker

    當(dāng)提交一個任務(wù)時,如果需要創(chuàng)建一個線程(何時需要在下一節(jié)中探討)時,就調(diào)用線程工廠創(chuàng)建一個線程,同時將線程綁定到Worker工作隊列中。需要說明的是,Worker隊列構(gòu)造的時候帶著一個任務(wù)Runnable,因此Worker創(chuàng)建時總是綁定著一個待執(zhí)行任務(wù)。換句話說,創(chuàng)建線程的前提是有必要創(chuàng)建線程(任務(wù)數(shù)已經(jīng)超出了線程或者強制創(chuàng)建新的線程,至于為何強制創(chuàng)建新的線程后面章節(jié)會具體分析),不會無緣無故創(chuàng)建一堆空閑線程等著任務(wù)。這是節(jié)省資源的一種方式。

    一旦線程池啟動線程后(調(diào)用線程run())方法,那么線程工作隊列Worker就從第1個任務(wù)開始執(zhí)行(這時候發(fā)現(xiàn)構(gòu)造Worker時傳遞一個任務(wù)的好處了),一旦第1個任務(wù)執(zhí)行完畢,就從線程池的任務(wù)隊列中取出下一個任務(wù)進行執(zhí)行。循環(huán)如此,直到線程池被關(guān)閉或者任務(wù)拋出了一個RuntimeException。

    由此可見,線程池的基本原理其實也很簡單,無非預(yù)先啟動一些線程,線程進入死循環(huán)狀態(tài),每次從任務(wù)隊列中獲取一個任務(wù)進行執(zhí)行,直到線程池被關(guān)閉。如果某個線程因為執(zhí)行某個任務(wù)發(fā)生異常而終止,那么重新創(chuàng)建一個新的線程而已。如此反復(fù)。

    其實,線程池原理看起來簡單,但是復(fù)雜的是各種策略,例如何時該啟動一個線程,何時該終止、掛起、喚醒一個線程,任務(wù)隊列的阻塞與超時,線程池的生命周期以及任務(wù)拒絕策略等等。下一節(jié)將研究這些策略問題。

     

     



    ©2009-2014 IMXYLZ |求賢若渴
    posted on 2011-01-18 23:43 imxylz 閱讀(16111) 評論(6)  編輯  收藏 所屬分類: Java Concurrency

    評論

    # re: 深入淺出 Java Concurrency (33): 線程池 part 6 線程池的實現(xiàn)及原理 (1) 2011-01-19 02:36 電腦知識與技術(shù)博客
    真是太好了。非常詳細的技術(shù)文檔  回復(fù)  更多評論
      

    # re: 深入淺出 Java Concurrency (33): 線程池 part 6 線程池的實現(xiàn)及原理 (1)[未登錄] 2011-01-20 05:46 xiaoxiao
    thanks!  回復(fù)  更多評論
      

    # re: 深入淺出 Java Concurrency (33): 線程池 part 6 線程池的實現(xiàn)及原理 (1) 2011-03-30 15:38 現(xiàn)金流量表的編制方法
    真是太詳細了  回復(fù)  更多評論
      

    # re: 深入淺出 Java Concurrency (33): 線程池 part 6 線程池的實現(xiàn)及原理 (1)[未登錄] 2012-05-09 12:15 zym
    很感謝總結(jié)與分享,這個系列收獲很多  回復(fù)  更多評論
      

    # re: 深入淺出 Java Concurrency (33): 線程池 part 6 線程池的實現(xiàn)及原理 (1)[未登錄] 2014-05-08 11:31 nemo
    看完了這一篇,很詳細。

    有一個問題就是:Worker的數(shù)量是如何確定的,由哪個參數(shù)確定?

    Worker是在什么時候被構(gòu)造出來的?   回復(fù)  更多評論
      

    # re: 深入淺出 Java Concurrency (33): 線程池 part 6 線程池的實現(xiàn)及原理 (1) 2014-05-08 11:56 imxylz
    @nemo

    當(dāng)提交一個任務(wù)時,如果需要創(chuàng)建一個線程(何時需要在下一節(jié)中探討)時,就調(diào)用線程工廠創(chuàng)建一個線程,同時將線程綁定到Worker工作隊列中。

    線程池有兩個核心變量:corePoolSize與maximumPoolSize。

    下一頁描述的比較詳細:http://m.tkk7.com/xylz/archive/2011/02/11/344091.html  回復(fù)  更多評論
      


    ©2009-2014 IMXYLZ
    主站蜘蛛池模板: 亚洲码在线中文在线观看| 亚洲国产成人精品久久| 国产成人一区二区三区视频免费| 亚洲AV电影院在线观看| 在线观看免费人成视频色| 亚洲熟妇无码AV| 亚洲日韩涩涩成人午夜私人影院| 叮咚影视在线观看免费完整版| 亚洲码在线中文在线观看| 卡一卡二卡三在线入口免费| 国产黄在线播放免费观看| 久久99亚洲网美利坚合众国 | 国产卡二卡三卡四卡免费网址| 亚洲AV无码专区在线观看成人| 亚洲男同帅GAY片在线观看| 西西大胆无码视频免费| 二级毛片免费观看全程| 亚洲国产中文在线视频| 亚洲伊人久久综合影院| 18女人腿打开无遮掩免费| 窝窝影视午夜看片免费| 亚洲专区一路线二| 国产午夜亚洲精品午夜鲁丝片| 久久午夜免费视频| 91福利免费网站在线观看| 亚洲熟女综合色一区二区三区| 亚洲av伊人久久综合密臀性色| 免费黄色大片网站| 91高清免费国产自产拍2021| 一边摸一边桶一边脱免费视频| 久久精品国产亚洲AV忘忧草18| 亚洲熟女少妇一区二区| 国产禁女女网站免费看| 免费在线观看h片| 丁香花在线观看免费观看图片| 亚洲午夜精品久久久久久app| 久久久影院亚洲精品| 久久乐国产精品亚洲综合| 日本无吗免费一二区| 黄色永久免费网站| 日韩免费高清大片在线|