spring線程池ThreadPoolTaskExecutor

當我們需要實現(xiàn)并發(fā)、異步等操作時,通常都會使用到ThreadPoolTaskExecutor,現(xiàn)對其使用稍作總結。

配置

ThreadPoolTaskExecutor通常通過XML方式配置,或者通過Executors的工廠方法進行配置。
XML方式配置代碼如下:

<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
    <property name="corePoolSize" value="8"/> <!--核心線程數(shù) -->
    <property name="maxPoolSize" value="16"/> <!--最大線程數(shù) -->
    <property name="keepAliveSeconds" value ="3000"/> <!--線程最大空閑時間 -->
    <property name="queueCapacity" value="200"/> <!-- 隊列大小 -->
    <property name="threadNamePrefix" value="TASK_EXECUTOR"/>
    <property name="rejectedExecutionHandler">
        <bean class="java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy"/>
    </property>
</bean>

rejectedExecutionHandler字段用于配置拒絕策略,常用的拒絕策略如下:

  • AbortPolicy,用于被拒絕任務的處理程序,它將拋出RejectedExecutionException。
  • CallerRunsPolicy,用于被拒絕任務的處理程序,它直接在execute方法的調用線程中運行被拒絕的任務。
  • DiscardOldestPolicy,用于被拒絕任務的處理程序,它放棄最舊的未處理請求,然后重試execute。
  • DiscardPolicy,用于被拒絕任務的處理程序,默認情況下它將丟棄被拒絕的任務。

其他說明:

  1. 為了實現(xiàn)某些特殊的業(yè)務需求,用戶可以選擇使用自定義策略,只需實現(xiàn)RejectedExecutionHandler接口即可。
  2. 建議配置threadNamePrefix屬性,出問題時可以更方便的進行排查。

提交任務

  • 無返回值的任務使用execute(Runnable)
  • 有返回值的任務使用submit(Runnable)

處理流程

  1. 當一個任務被提交到線程池時,首先查看線程池的核心線程是否都在執(zhí)行任務,否就選擇一條線程執(zhí)行任務,是就執(zhí)行第二步。
  2. 查看核心線程池是否已滿,不滿就創(chuàng)建一條線程執(zhí)行任務,否則執(zhí)行第三步。
  3. 查看任務隊列是否已滿,不滿就將任務存儲在任務隊列中,否則執(zhí)行第四步。
  4. 查看線程池是否已滿,不滿就創(chuàng)建一條線程執(zhí)行任務,否則就按照策略處理無法執(zhí)行的任務。

在ThreadPoolExecutor中表現(xiàn)為:

  • 如果當前運行的線程數(shù)小于corePoolSize,那么就創(chuàng)建線程來執(zhí)行任務(執(zhí)行時需要獲取全局鎖)。
  • 如果運行的線程大于或等于corePoolSize,那么就把task加入BlockQueue。
  • 如果創(chuàng)建的線程數(shù)量大于BlockQueue的最大容量,那么創(chuàng)建新線程來執(zhí)行該任務。
  • 如果創(chuàng)建線程導致當前運行的線程數(shù)超過maximumPoolSize,就根據(jù)飽和策略來拒絕該任務。

關閉線程池

調用shutdown或者shutdownNow,兩者都不會接受新的任務,而且通過調用要停止線程的interrupt方法來中斷線程,有可能線程永遠不會被中斷,不同之處在于shutdownNow會首先將線程池的狀態(tài)設置為STOP,然后嘗試停止所有線程(有可能導致部分任務沒有執(zhí)行完)然后返回未執(zhí)行任務的列表。而shutdown則只是將線程池的狀態(tài)設置為shutdown,然后中斷所有沒有執(zhí)行任務的線程,并將剩余的任務執(zhí)行完。

配置線程個數(shù)

  • 如果是CPU密集型任務,那么線程池的線程個數(shù)應該盡量少一些,一般為CPU的個數(shù)+1條線程。
  • 如果是IO密集型任務,那么線程池的線程可以放的很大,如2*CPU的個數(shù)。
  • 對于混合型任務,如果可以拆分的話,通過拆分成CPU密集型和IO密集型兩種來提高執(zhí)行效率;如果不能拆分的的話就可以根據(jù)實際情況來調整線程池中線程的個數(shù)。

監(jiān)控線程池狀態(tài)

常用狀態(tài):

  • taskCount:線程需要執(zhí)行的任務個數(shù)。
  • completedTaskCount:線程池在運行過程中已完成的任務數(shù)。
  • largestPoolSize:線程池曾經創(chuàng)建過的最大線程數(shù)量。
  • getPoolSize獲取當前線程池的線程數(shù)量。
  • getActiveCount:獲取活動的線程的數(shù)量
    日志再解讀
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容