線程池相關-個人總結

線程池的7個參數的理解

ThreadPoolExecutor mExecutor = new ThreadPoolExecutor(corePoolSize,// 核心線程數
						maximumPoolSize, // 最大線程數
						keepAliveTime, // 閒置線程存活時間
						TimeUnit.MILLISECONDS,// 時間單位
						new LinkedBlockingDeque<Runnable>(),// 線程隊列
						Executors.defaultThreadFactory(),// 線程工廠
						new AbortPolicy()// 隊列已滿,而且當前線程數已經超過最大線程數時的異常處理策略
				);

如何配置

在applicationContext.xml中配置bean

<!--Spring線程池-->
    <bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
        <!-- 核心線程數 -->
        <property name="corePoolSize" value="5" />
        <!-- 線程池維護線程的最大數量 -->
        <property name="maxPoolSize" value="100" />
        <!-- 允許的空閒時間, 默認60秒 -->
        <property name="keepAliveSeconds" value="60" />
        <!-- 緩存隊列長度 -->
        <property name="queueCapacity" value="50" />
        <!-- 線程超過空閒時間限制,均會退出直到線程數量爲0 -->
        <property name="allowCoreThreadTimeOut" value="true"/>
        <!-- 對拒絕task的處理策略 -->
        <property name="rejectedExecutionHandler">
            <bean class="java.util.concurrent.ThreadPoolExecutor.DiscardOldestPolicy" />
        </property>
    </bean>

workQueue: 線程池所使用的緩衝隊列

        直接提交 SynchronousQueue

該隊列是將任務直接提交給線程而不保存它們。在此,如果不存在空閒的線程,則試圖把任務加入隊列將失敗,因此會構造一個新的線程。此策略可以避免在處理可能具有內部依賴性的請求集時出現鎖。直接提交通常要求無界 maximumPoolSizes 以避免拒絕新提交的任務。當命令以超過隊列所能處理的平均數連續到達時,此策略允許無界線程具有增長的可能性。           SynchronousQueue線程安全的Queue,可以存放若干任務(但當前只允許有且只有一個任務在等待),其中每個插入操作必須等待另一個線程的對應移除操作,也就是說A任務進入隊列,B任務必須等A任務被移除之後才能進入隊列,否則執行異常策略。你來一個我扔一個,所以說SynchronousQueue沒有任何內部容量。

       比如:核心線程數爲2,最大線程數爲3;使用SynchronousQueue。

       當前有2個核心線程在運行,又來了個A任務,兩個核心線程沒有執行完當前任務,根據如果運行的線程等於或多於 corePoolSize,

      則 Executor 始終首選將請求加入隊列,而不添加新的線程。所以A任務被添加到隊列,此時的隊列是SynchronousQueue,

      當前不存在可用於立即運行任務的線程,因此會構造一個新的線程,此時又來了個B任務,兩個核心線程還沒有執行完。

       新創建的線程正在執行A任務,所以B任務進入Queue後,最大線程數爲3,發現沒地方仍了。就只能執行異常策略(RejectedExecutionException)。
 

        無界隊列 如LinkedBlockingQueue

使用無界隊列(例如,不具有預定義容量的 LinkedBlockingQueue)將導致在所有核心線程都在忙時新任務在隊列中等待。這樣,創建的線程就不會超過 corePoolSize。(因此,maximumPoolSize 的值也就沒意義了。)也就不會有新線程被創建,都在那等着排隊呢。如果未指定容量,則它等於 Integer.MAX_VALUE。如果設置了Queue預定義容量,則當核心線程忙碌時,新任務會在隊列中等待,直到超過預定義容量(新任務沒地方放了),纔會執行異常策略。你來一個我接一個,直到我容不下你了。FIFO,先進先出
 

 

    有界隊列 如ArrayBlockingQueue

操作模式跟LinkedBlockingQueue查不多,只不過必須爲其設置容量。所以叫有界隊列。new ArrayBlockingQueue<Runnable>(Integer.MAX_VALUE) 跟 new LinkedBlockingQueue(Integer.MAX_VALUE)效果一樣。LinkedBlockingQueue 底層是鏈表結構,ArrayBlockingQueue  底層是數組結構。你來一個我接一個,直到我容不下你了。FIFO,先進先出。
 

ThreadPoolTaskExecutor的拒絕策略


rejectedExectutionHandler參數字段用於配置絕策略,常用拒絕策略如下

AbortPolicy:用於被拒絕任務的處理程序,它將拋出RejectedExecutionException

CallerRunsPolicy:用於被拒絕任務的處理程序,它直接在execute方法的調用線程中運行被拒絕的任務。

DiscardOldestPolicy:用於被拒絕任務的處理程序,它放棄最舊的未處理請求,然後重試execute。

DiscardPolicy:用於被拒絕任務的處理程序,默認情況下它將丟棄被拒絕的任務
 

線程池的執行流程如下

1.當一個任務被提交到線程池時,首先查看線程池的核心線程是否都在執行任務,否就選擇一條線程執行任務,是就執行第二步。
2.查看核心線程池是否已滿,不滿就創建一條線程執行任務,否則執行第三步。
3.查看任務隊列是否已滿,不滿就將任務存儲在任務隊列中,否則執行第四步。
4.查看線程池是否已滿,不滿就創建一條線程執行任務,否則就按照策略處理無法執行的任務。
在ThreadPoolExecutor中表現爲:
1.如果當前運行的線程數小於corePoolSize,那麼就創建線程來執行任務(執行時需要獲取全局鎖)。
2.如果運行的線程大於或等於corePoolSize,那麼就把task加入BlockQueue。
3.如果創建的線程數量大於BlockQueue的最大容量,那麼創建新線程來執行該任務。
4.如果創建線程導致當前運行的線程數超過maximumPoolSize,就根據飽和策略來拒絕該任務。
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章