線程池內部工做原理

成功只有一個——按照本身的方式,去度過人生。面試

隨着cpu核數愈來愈多,不可避免的利用多線程技術以充分利用其計算能力。因此,多線程技術是服務端開發人員必須掌握的技術。多線程

線程的建立和銷燬,都涉及到系統調用,比較消耗系統資源,因此就引入了線程池技術,避免頻繁的線程建立和銷燬。工具

在Java中有一個Executors工具類,能夠爲咱們建立一個線程池,其本質就是new了一個ThreadPoolExecutor對象。線程池幾乎也是面試必考問題。本節結合源代碼,說說ThreadExecutor的工做原理spa

1、線程池建立

先看一下ThreadPoolExecutor參數最全的構造方法:線程

public ThreadPoolExecutor(int corePoolSize,
            int maximumPoolSize,
            long keepAliveTime,
            TimeUnit unit,
            BlockingQueue<Runnable> workQueue,
            ThreadFactory threadFactory,
            RejectedExecutionHandler handler) {
            //...
}
  • corePoolSize:線程池的核心線程數,說白了就是,即使是線程池裏沒有任何任務,也會有corePoolSize個線程在候着等任務。
  • maximumPoolSize:最大線程數,無論你提交多少任務,線程池裏最多工做線程數就是maximumPoolSize。
  • keepAliveTime:線程的存活時間。當線程池裏的線程數大於corePoolSize時,若是等了keepAliveTime時長尚未任務可執行,則線程退出。
  • unit:這個用來指定keepAliveTime的單位,好比秒:TimeUnit.SECONDS。
  • workQueue:一個阻塞隊列,提交的任務將會被放到這個隊列裏。
  • threadFactory:線程工廠,用來建立線程,主要是爲了給線程起名字,默認工廠的線程名字:pool-1-thread-3。
  • handler:拒絕策略,當線程池裏線程被耗盡,且隊列也滿了的時候會調用。

以上就是建立線程池時用到的參數,面試中常常會有面試官問到這個問題。3d

2、線程池執行流程

這裏用一個圖來講明線程池的執行流程
image
任務被提交到線程池,會先判斷當前線程數量是否小於corePoolSize,若是小於則建立線程來執行提交的任務,不然將任務放入workQueue隊列,若是workQueue滿了,則判斷當前線程數量是否小於maximumPoolSize,若是小於則建立線程執行任務,不然就會調用handler,以表示線程池拒絕接收任務。code

這裏以jdk1.8.0_111的源代碼爲例,看一下具體實現。對象

一、先看一下線程池的executor方法

image

  • 判斷當前活躍線程數是否小於corePoolSize,若是小於,則調用addWorker建立線程執行任務
  • 若是不小於corePoolSize,則將任務添加到workQueue隊列。
  • 若是放入workQueue失敗,則建立線程執行任務,若是這時建立線程失敗(當前線程數不小於maximumPoolSize時),就會調用reject(內部調用handler)拒絕接受任務。

二、再看下addWorker的方法實現

image
這塊代碼是在建立非核心線程時,即core等於false。判斷當前線程數是否大於等於maximumPoolSize,若是大於等於則返回false,即上邊說到的③中建立線程失敗的狀況。blog

addWorker方法的下半部分:
image隊列

  • 建立Worker對象,同時也會實例化一個Thread對象。
  • 啓動啓動這個線程

三、再到Worker裏看看其實現

image
能夠看到在建立Worker時會調用threadFactory來建立一個線程。上邊的②中啓動一個線程就會觸發Worker的run方法被線程調用。

四、接下來我們看看runWorker方法的邏輯

image
線程調用runWoker,會while循環調用getTask方法從workerQueue裏讀取任務,而後執行任務。只要getTask方法不返回null,此線程就不會退出。

五、最後在看看getTask方法實現

image

  • 我們先無論allowCoreThreadTimeOut,這個變量默認值是false。wc>corePoolSize則是判斷當前線程數是否大於corePoolSize。
  • 若是當前線程數大於corePoolSize,則會調用workQueue的poll方法獲取任務,超時時間是keepAliveTime。若是超過keepAliveTime時長,poll返回了null,上邊提到的while循序就會退出,線程也就執行完了。

若是當前線程數小於corePoolSize,則會調用workQueue的take方法阻塞在當前。

相關文章
相關標籤/搜索