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

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

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

    xylz,imxylz

    關注后端架構、中間件、分布式和并發編程

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

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


    線程池數據結構與線程構造方法

    由于已經看到了ThreadPoolExecutor的源碼,因此很容易就看到了ThreadPoolExecutor線程池的數據結構。圖1描述了這種數據結構。

    ThreadPoolExecutor

    圖1 ThreadPoolExecutor 數據結構

    其實,即使沒有上述圖形描述ThreadPoolExecutor的數據結構,我們根據線程池的要求也很能夠猜測出其數據結構出來。

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

     

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

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

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

     

    ThreadPoolExecutor使用一個線程工廠來構造線程。線程池都是提交一個任務Runnable,然后在某一個線程Thread中執行,ThreadFactory 負責如何創建一個新線程。

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

    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;
        }
    }

     

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

    線程池中線程生命周期

    一個線程Worker被構造出來以后就開始處于運行狀態。以下是一個線程執行的簡版邏輯。

    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

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

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

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

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

     

     



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

    評論

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

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

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

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

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

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

    Worker是在什么時候被構造出來的?   回復  更多評論
      

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

    當提交一個任務時,如果需要創建一個線程(何時需要在下一節中探討)時,就調用線程工廠創建一個線程,同時將線程綁定到Worker工作隊列中。

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

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


    ©2009-2014 IMXYLZ
    主站蜘蛛池模板: 久久九九全国免费| 牛牛在线精品观看免费正| 免费无遮挡无码永久视频| 人人狠狠综合久久亚洲婷婷| jizz免费观看| 国产亚洲AV无码AV男人的天堂| 黄桃AV无码免费一区二区三区| 亚洲伊人久久大香线蕉综合图片| 一本大道一卡二大卡三卡免费| 国产亚洲精品AA片在线观看不加载 | 久久精品国产亚洲av麻豆蜜芽 | 亚洲AⅤ永久无码精品AA| 免费看黄网站在线看 | 国产V亚洲V天堂A无码| 拍拍拍无挡视频免费观看1000| 国产亚洲一区二区精品| 好久久免费视频高清| 亚洲无成人网77777| 国产成人免费在线| 亚洲日韩av无码中文| 日韩亚洲国产综合久久久| 18禁超污无遮挡无码免费网站| 亚洲免费视频在线观看| 无码国产精品一区二区免费虚拟VR| 亚洲综合一区无码精品| 免费又黄又爽的视频| 成人久久免费网站| 2017亚洲男人天堂一| 亚洲精品国产成人影院| 免费A级毛片无码视频| 亚洲av永久中文无码精品综合| 亚洲精品无码成人片在线观看| 未满十八18禁止免费无码网站 | 免费观看四虎精品国产永久| 东北美女野外bbwbbw免费| 亚洲福利视频一区二区三区| 国产美女精品视频免费观看| 成全视频高清免费观看电视剧| 亚洲一区二区三区久久| 亚洲综合色区在线观看| 国产精品成人免费福利|