<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
    主站蜘蛛池模板: 色窝窝免费一区二区三区| 无码精品国产一区二区三区免费| 91网站免费观看| 亚洲色av性色在线观无码| 拍拍拍无挡视频免费观看1000| 亚洲一区二区三区无码中文字幕| 国产乱子伦精品免费视频| 亚洲中文字幕无码久久2017| 最近免费字幕中文大全| 亚洲AV无码第一区二区三区 | 免费一级成人毛片| 一级片在线免费看| 亚洲精品无码专区在线在线播放| a毛片免费在线观看| 亚洲黄色免费在线观看| 久久精品a一国产成人免费网站 | 91精品国产免费久久久久久青草| 亚洲天堂2016| 免费国产a国产片高清网站| 亚洲日韩在线观看免费视频| 亚洲成年人在线观看| 四虎永久在线观看免费网站网址| 亚洲人成色99999在线观看| 亚洲成a人片在线观看日本麻豆| 国产精品免费久久久久影院| 日韩精品亚洲人成在线观看| 国产精品视频免费一区二区| 免费无遮挡无遮羞在线看| 亚洲不卡av不卡一区二区| a毛片基地免费全部视频| 免费在线观看自拍性爱视频| 亚洲AV福利天堂一区二区三| 午夜无遮挡羞羞漫画免费| 人人公开免费超级碰碰碰视频| 亚洲Av无码专区国产乱码DVD | 一级女性全黄久久生活片免费| 亚洲精品国产精品乱码不99| 免费国产黄线在线观看| 一个人免费观看视频在线中文| 久久精品国产亚洲av水果派| 全部免费国产潢色一级|