日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

JAVA线程池(ThreadPoolExecutor)源码分析

發布時間:2025/6/15 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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線程池原理的朋友們有一點幫助。

    總結

    以上是生活随笔為你收集整理的JAVA线程池(ThreadPoolExecutor)源码分析的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。