JAVA线程池(ThreadPoolExecutor)源码分析
生活随笔
收集整理的這篇文章主要介紹了
JAVA线程池(ThreadPoolExecutor)源码分析
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
JAVA5提供了多種類型的線程池,如果你對這些線程池的特點以及類型不太熟悉或者非常熟悉,請幫忙看看這篇文章(順便幫忙解決里面存在的問題,謝謝!):
????http://xtu-xiaoxin.iteye.com/admin/blogs/647580
????
??? 如果對ThreadPoolExecutor還不是很熟悉,可以看看一篇對ThreadPoolExecutor的介紹的博文:
http://blog.csdn.net/waterbig/archive/2009/11/10/4794244.aspx
??? 首先,JAVA 中使用ThreadPoolExecutor的常用方式:
??? 實例代碼1?
Java代碼 ? Runnable?runnable?=?new?CountService(intArr);?? ???????ThreadPoolExecutor?execute?=?(ThreadPoolExecutor)Executors.newFixedThreadPool(10);?? ???????//或者使用:ThreadPoolExecutor?execute?=?(ThreadPoolExecutor)Executors.newCachedThreadPool();?? ???????execute.submit(runnable);??
???? 在分析ThreadPoolExecutor源碼前,先了解下面兩個概念:
???? 1.核心線程(任務):我們定義的線程,即實現了Runnable接口的類,是我們將要放到線程池中執行的類,如實例代碼中的CountService類
???? 2.工作線程:由線程池中創建的線程,是用來獲得核心線程并執行核心線程的線程(比較拗口哦,具體看代碼就知道是什么東東了)。
??? Executors是一個線程池工廠,各種類型的線程池都是通過它來創建的,注意把它和Executor分開,感覺這個線程池工廠命名有點問題。
??? 我們主要分析下我們提交任務的處理邏輯,即’execute.submit(runnable)’的實現。
Submit()方法是在ThreadPoolExecutor繼承的抽象類AbstractExecutorService中實現的,具體代碼如下:
?? Java代碼 ? public?Future<?>?submit(Runnable?task)?{?? ????????if?(task?==?null)?throw?new?NullPointerException();?? ???????//對核心線程的一個包裝,RunnableFuture還是一個Runnable?? ????????RunnableFuture<Object>?ftask?=?newTaskFor(task,?null);?? ???????//核心線程執行邏輯?? ????????execute(ftask);?? ????????return?ftask;?? ????}??
???? 從代碼中可以看出,線程的執行邏輯通過execute()完成,而execute是在AbstractExecutorService的子類ThreadPoolExecutor中實現的。看,一個典型的模板模式!廢話少說,下面看ThreadPoolExecutor中execute()方法中代碼:
???
??? Java代碼 ? public?void?execute(Runnable?command)?{?? ????????if?(command?==?null)?? ????????????throw?new?NullPointerException();?? ????????/*? ?????????*?command線程運行的整個邏輯在?addIfUnderCorePoolSize(command)方法中實現? ?????????*?一般適用于FixedThreadPool? ?????????*/?? ????????if?(poolSize?>=?corePoolSize?||?!addIfUnderCorePoolSize(command))?{?? ????????????/*? ?????????????*?poolSize?>=?corePoolSize條件成立情景:當創建的為CacheThreadPool時,條件? ?????????????*?就能成立? ?????????????*/?? ????????????if?(runState?==?RUNNING?&&?workQueue.offer(command))?{?? ????????????????if?(runState?!=?RUNNING?||?poolSize?==?0)?? ????????????????????//兩種情況下執行該方法:1.線程池shutdown??2.CacheThreadPool中第一個核心線程的執行?? ????????????????????ensureQueuedTaskHandled(command);?? ????????????}?? ????????????//CacheThreadPool中線程的執行邏輯?? ????????????else?if?(!addIfUnderMaximumPoolSize(command))?? ????????????????reject(command);?//?is?shutdown?or?saturated?? ????????}?? ????}??
???? 注意:CachedThreadPool和FixedThreadPool的邏輯實現都是在ThreadPoolExecutor中實現的。它兩的主要區別就是屬性corePoolSize以及workQueue的初始值的不同。具體可自己查看工程類Executors的newFixedThreadPool()和newCachedThreadPool方法。由于這些初始值的不同,所以實現的邏輯也不同,具體的我在代碼中已經注釋了。
??? command線程運行的整個邏輯在 addIfUnderCorePoolSize(command)方法中實現的,
詳細請看addIfUnderCorePoolSize(command)源碼:
? Java代碼 ? private?boolean?addIfUnderCorePoolSize(Runnable?firstTask)?{?? ???????Thread?t?=?null;?? ???????final?ReentrantLock?mainLock?=?this.mainLock;?? ???????mainLock.lock();?? ???????try?{?? ????????//poolSize?<?corePoolSize?即當前工作線程的數量一定要小于你設置的線程最大數量?? ????????//CachedThreadPool永遠也不會進入該方法,因為它的corePoolSize初始為0?? ???????????if?(poolSize?<?corePoolSize?&&?runState?==?RUNNING)?? ???????????????t?=?addThread(firstTask);?? ???????}?finally?{?? ???????????mainLock.unlock();?? ???????}?? ???????if?(t?==?null)?? ???????????return?false;?? ???????t.start();???//線程執行了?? ???????return?true;?? ???}??
???? 看’t.start()’,這表示工作線程啟動了,工作線程t啟動的前提條件是’t = addThread(firstTask); ‘返回值t必須不為null。好了,現在想看看java線程池中工作線程是怎么樣的嗎?請看addThread方法:
??? Java代碼 ? private?Thread?addThread(Runnable?firstTask)?{?? ????//Worker就是典型的工作線程,所以的核心線程都在工作線程中執行?? ???????Worker?w?=?new?Worker(firstTask);?? ???????//采用默認的線程工廠生產出一線程。注意就是設置一些線程的默認屬性,如優先級、是否為后臺線程等?? ???????Thread?t?=?threadFactory.newThread(w);??? ???????if?(t?!=?null)?{?? ???????????w.thread?=?t;?? ???????????workers.add(w);?? ?????????//沒生成一個工作線程?poolSize加1,但poolSize等于最大線程數corePoolSize時,則不能再生成工作線程?? ???????????int?nt?=?++poolSize;???? ???????????if?(nt?>?largestPoolSize)?? ???????????????largestPoolSize?=?nt;?? ???????}?? ???????return?t;?? ???}??
??? 看見沒,Worker就是工作線程類,它是ThreadPoolExecutor中的一個內部類。下面,我們主要分析Worker類,如了解了Worker類,那基本就了解了java線程池的整個原理了。不用怕,Worker類的邏輯很簡單,它其實就是一個線程,實現了Runnable接口的,所以,我們先從run方法入手,run方法源碼如下:
? Java代碼 ? public?void?run()?{?? ????????????try?{?? ????????????????Runnable?task?=?firstTask;?? ????????????????firstTask?=?null;?? ????????????????/**? ?????????????????*?注意這段while循環的執行邏輯,沒執行完一個核心線程后,就會去線程池? ?????????????????*?隊列中取下一個核心線程,如取出的核心線程為null,則當前工作線程終止? ?????????????????*/?? ????????????????while?(task?!=?null?||?(task?=?getTask())?!=?null)?{?? ????????????????????runTask(task);??//你所提交的核心線程(任務)的運行邏輯?? ????????????????????task?=?null;?? ????????????????}?? ????????????}?finally?{?? ????????????????workerDone(this);?//?當前工作線程退出?? ????????????}?? ????????}?? ????}??
???? 從源碼中可看出,我們所提交的核心線程(任務)的邏輯是在Worker中的runTask()方法中實現的。這個方法很簡單,自己可以打開看看。這里要注意一點,在runTask()方法中執行核心線程時是調用核心線程的run()方法,這是一個尋常方法的調用,千萬別與線程的啟動(start())混合了。這里還有一個比較重要的方法,那就是上述代碼中while循環中的getTask()方法,它是一個從池隊列中取的核心線程(任務)的方法。具體代碼如下:
??? Java代碼 ? Runnable?getTask()?{?? ????????for?(;;)?{?? ????????????try?{?? ????????????????int?state?=?runState;?? ????????????????if?(state?>?SHUTDOWN)???? ????????????????????return?null;?? ????????????????Runnable?r;?? ????????????????if?(state?==?SHUTDOWN)??//幫助清空隊列?? ????????????????????r?=?workQueue.poll();?? ???????????????/*? ????????????????*?對于條件1,如果可以超時,則在等待keepAliveTime時間后,則返回一null對象,這時就? ????????????????*??銷毀該工作線程,這就是CachedThreadPool為什么能回收空閑線程的原因了。? ????????????????*?注意以下幾點:1.這種功能情況一般不可能在fixedThreadPool中出現? ????????????????*????????????2.在使用CachedThreadPool時,條件1一般總是成立,因為CachedThreadPool的corePoolSize? ????????????????*??????????????初始為0? ????????????????*/?? ????????????????else?if?(poolSize?>?corePoolSize?||?allowCoreThreadTimeOut)??//------------------條件1?? ????????????????????r?=?workQueue.poll(keepAliveTime,?TimeUnit.NANOSECONDS);???? ????????????????else?? ????????????????????r?=?workQueue.take();???????//如果隊列不存在任何元素?則一直等待。?FiexedThreadPool典型模式----------條件2?? ????????????????if?(r?!=?null)?? ????????????????????return?r;?? ????????????????if?(workerCanExit())?{???????//--------------------------條件3?? ????????????????????if?(runState?>=?SHUTDOWN)?//?Wake?up?others?? ????????????????????????interruptIdleWorkers();?? ????????????????????return?null;?? ????????????????}?? ????????????????//?Else?retry?? ????????????}?catch?(InterruptedException?ie)?{?? ????????????????//?On?interruption,?re-check?runState?? ????????????}?? ????????}?? ????}??
???? 從這個方法中,我們需要了解一下幾點:
??? 1.CachedThreadPool獲得任務邏輯是條件1,條件1的處理邏輯請看注釋,CachedThreadPool執行條件1的原因是:CachedThreadPool的corePoolSize時刻為0。
??? 2.FixedThreadPool執行的邏輯為條件2,從’workQueue.take()’中我們就明白了為什么FixedThreadPool不會釋放工作線程的原因了(除非你關閉線程池)。
??? 最后,我們了解下Worker(工作線程)終止時的處理吧,這個對理解CachedThreadPool有幫助,具體代碼如下:
??? Java代碼 ? /**? ????*?工作線程退出要處理的邏輯? ????*?@param?w? ????*/?? ???void?workerDone(Worker?w)?{?? ???????final?ReentrantLock?mainLock?=?this.mainLock;?? ???????mainLock.lock();?? ???????try?{?? ???????????completedTaskCount?+=?w.completedTasks;??? ???????????workers.remove(w);??//從工作線程緩存中刪除?? ???????????if?(--poolSize?==?0)?//poolSize減一,這時其實又可以創建工作線程了?? ???????????????tryTerminate();?//嘗試終止?? ???????}?finally?{?? ???????????mainLock.unlock();?? ???????}?? ???}??
???? 注意workDone()方法中的tyrTerminate()方法,它是你以后理解線程池中shuDown()以及CachedThreadPool原理的關鍵,具體代碼如下: ???
??? Java代碼 ? private?void?tryTerminate()?{?? ????//終止的前提條件就是線程池里已經沒有工作線程(Worker)了?? ???????if?(poolSize?==?0)?{?? ???????????int?state?=?runState;?? ???????????/**? ????????????*?如果當前已經沒有了工作線程(Worker),但是線程隊列里還有等待的線程任務,則創建一個? ????????????*?工作線程來執行線程隊列中等待的任務? ????????????*/?? ???????????if?(state?<?STOP?&&?!workQueue.isEmpty())?{?????? ???????????????state?=?RUNNING;?//?disable?termination?check?below?? ???????????????Thread?t?=?addThread(null);?? ???????????????if?(t?!=?null)?? ???????????????????t.start();?? ???????????}?? ???????????//設置池狀態為終止狀態?? ???????????if?(state?==?STOP?||?state?==?SHUTDOWN)?{?? ???????????????runState?=?TERMINATED;?? ???????????????termination.signalAll();??? ???????????????terminated();??? ???????????}?? ???????}?? ???}??
???? 第一次寫這么長的博文,還是躲著項目經理寫的,真不容易,希望能對想了解java線程池原理的朋友們有一點幫助。
????http://xtu-xiaoxin.iteye.com/admin/blogs/647580
????
??? 如果對ThreadPoolExecutor還不是很熟悉,可以看看一篇對ThreadPoolExecutor的介紹的博文:
http://blog.csdn.net/waterbig/archive/2009/11/10/4794244.aspx
??? 首先,JAVA 中使用ThreadPoolExecutor的常用方式:
??? 實例代碼1?
Java代碼 ?
???? 在分析ThreadPoolExecutor源碼前,先了解下面兩個概念:
???? 1.核心線程(任務):我們定義的線程,即實現了Runnable接口的類,是我們將要放到線程池中執行的類,如實例代碼中的CountService類
???? 2.工作線程:由線程池中創建的線程,是用來獲得核心線程并執行核心線程的線程(比較拗口哦,具體看代碼就知道是什么東東了)。
??? Executors是一個線程池工廠,各種類型的線程池都是通過它來創建的,注意把它和Executor分開,感覺這個線程池工廠命名有點問題。
??? 我們主要分析下我們提交任務的處理邏輯,即’execute.submit(runnable)’的實現。
Submit()方法是在ThreadPoolExecutor繼承的抽象類AbstractExecutorService中實現的,具體代碼如下:
?? Java代碼 ?
???? 從代碼中可以看出,線程的執行邏輯通過execute()完成,而execute是在AbstractExecutorService的子類ThreadPoolExecutor中實現的。看,一個典型的模板模式!廢話少說,下面看ThreadPoolExecutor中execute()方法中代碼:
???
??? Java代碼 ?
???? 注意:CachedThreadPool和FixedThreadPool的邏輯實現都是在ThreadPoolExecutor中實現的。它兩的主要區別就是屬性corePoolSize以及workQueue的初始值的不同。具體可自己查看工程類Executors的newFixedThreadPool()和newCachedThreadPool方法。由于這些初始值的不同,所以實現的邏輯也不同,具體的我在代碼中已經注釋了。
??? command線程運行的整個邏輯在 addIfUnderCorePoolSize(command)方法中實現的,
詳細請看addIfUnderCorePoolSize(command)源碼:
? Java代碼 ?
???? 看’t.start()’,這表示工作線程啟動了,工作線程t啟動的前提條件是’t = addThread(firstTask); ‘返回值t必須不為null。好了,現在想看看java線程池中工作線程是怎么樣的嗎?請看addThread方法:
??? Java代碼 ?
??? 看見沒,Worker就是工作線程類,它是ThreadPoolExecutor中的一個內部類。下面,我們主要分析Worker類,如了解了Worker類,那基本就了解了java線程池的整個原理了。不用怕,Worker類的邏輯很簡單,它其實就是一個線程,實現了Runnable接口的,所以,我們先從run方法入手,run方法源碼如下:
? Java代碼 ?
???? 從源碼中可看出,我們所提交的核心線程(任務)的邏輯是在Worker中的runTask()方法中實現的。這個方法很簡單,自己可以打開看看。這里要注意一點,在runTask()方法中執行核心線程時是調用核心線程的run()方法,這是一個尋常方法的調用,千萬別與線程的啟動(start())混合了。這里還有一個比較重要的方法,那就是上述代碼中while循環中的getTask()方法,它是一個從池隊列中取的核心線程(任務)的方法。具體代碼如下:
??? Java代碼 ?
???? 從這個方法中,我們需要了解一下幾點:
??? 1.CachedThreadPool獲得任務邏輯是條件1,條件1的處理邏輯請看注釋,CachedThreadPool執行條件1的原因是:CachedThreadPool的corePoolSize時刻為0。
??? 2.FixedThreadPool執行的邏輯為條件2,從’workQueue.take()’中我們就明白了為什么FixedThreadPool不會釋放工作線程的原因了(除非你關閉線程池)。
??? 最后,我們了解下Worker(工作線程)終止時的處理吧,這個對理解CachedThreadPool有幫助,具體代碼如下:
??? Java代碼 ?
???? 注意workDone()方法中的tyrTerminate()方法,它是你以后理解線程池中shuDown()以及CachedThreadPool原理的關鍵,具體代碼如下: ???
??? Java代碼 ?
???? 第一次寫這么長的博文,還是躲著項目經理寫的,真不容易,希望能對想了解java線程池原理的朋友們有一點幫助。
總結
以上是生活随笔為你收集整理的JAVA线程池(ThreadPoolExecutor)源码分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《Java编程思想》学习笔记9——集合容
- 下一篇: java集合框架类源代码阅读体会