四 Java多線程-ThreadPool線程池-2

線程池是個神器 , 用得好會非常地方便 。本來覺得線程池的構造器有些復雜,即使講清楚了對今后的用處可能也不太大,因為有一些Java定義好的線程池可以直接使用 。但是(凡事總有個但是),還是覺得講一講可能跟有助于理解后面的常用線程池,所以該打臉還是打吧
因為直接結合代碼看會更清楚一些,所以我把帶注釋的代碼貼出來:
public class ThreadPoolExecutor {public ThreadPoolExecutor(/*** corePoolSize:初始化時指定的核心線程數,包括空閑線程,必須大于等于0 , 當有新任務提交時,會執行以下判斷(workCount為當前活躍的線程數量):* 當workCount< corePoolSize:即使線程池中有空閑線程,也會創建新線程* 當corePoolSize ≤ workCount < maximumPoolSize:只有workQueue滿時才創建新線程* 當corePoolSize < workCount < maximumPoolSize:且超過corePoolSize部分的線程空閑時間達到keepAliveTime時,就回收這些線程,當設置allowCoreThreadTimeOut(true)時,*線程池中corePoolSize范圍內的線程空閑時間達到keepAliveTime也將被回收* 當設置corePoolSize == maximumPoolSize:線程池的大小固定,此時如有新任務提交,且workQueue未滿時,會將請求放入workQueue,等待有空閑的線程從workQueue中取任務并處理* 當workCount ≥ maximumPoolSize:若workQueue滿,則采取handler對應的策略*/int corePoolSize,// maximumPoolSize:初始化時指定的最大線程數量int maximumPoolSize,// keepAliveTime:線程池維護線程所允許的空閑時間 。當線程池中的線程數量大于corePoolSize時,如果這時沒有新的任務提交,核心線程外的線程不會立即銷毀,而是等待,直到等待的時間超過了keepAliveTimelong keepAliveTime,// 空閑時間單位TimeUnit unit,/*** workQueue:阻塞隊列的類型是保存等待執行的任務的阻塞隊列,主要有四種提交方式:* SynchronousQueue:同步隊列,這個“隊列”內部只包含了一個元素,隊列的size始終為0,每執行一個put,就需要一個take來解除阻塞,反之也一樣 。飽和狀態下,線程池能處理的最大線程數量為maximumPoolSize*使用SynchronousQueue隊列,提交的任務不會保存,而是會馬上提交執行*需要對程序的并發量有個準確的評估,才能設置合適的maximumPoolSize數量 , 否則很容易就會執行拒絕策略* ArrayBlockingQueue:有界任務隊列,飽和狀態下 , 線程池能處理的最大線程數量為maximumPoolSize + ArrayBlockingQueue.SIZE* LinkedBlockingQueue:無界任務隊列,線程池的任務隊列可以無限制的添加新的任務 , 此時線程池能夠創建的最大線程數是corePoolSize , *而maximumPoolSize就無效了,線程池飽和狀態下能處理的最大線程數量只取決于系統的性能* PriorityBlockingQueue:優先任務隊列 , 同LinkedBlockingQueue一樣,它也是一個無界的任務隊列,只不過需要自己實現元素的Comparable排序接口*/BlockingQueue<Runnable> workQueue,// threadFactory:創建新線程,使新創建的線程有相同的優先級且為非守護線程,同時設置線程的名稱,默認使用Executors.DefaultThreadFactory類創建ThreadFactory threadFactory,/*** handler:表示線程池的飽和策略,意思就是如果阻塞隊列滿了并且沒有空閑的線程,此時如果繼續提交任務,就需要采取一種策略處理該任務,線程池提供了4種策略* AbortPolicy:直接拋出異常,這是默認策略* CallerRunsPolicy:如果線程池的線程數量達到上限,則把任務隊列中的任務放在調用者的線程當運行* DiscardOldestPolicy:丟棄阻塞隊列中靠最前的任務,并執行當前任務* DiscardPolicy:直接丟棄任務*/RejectedExecutionHandler handler) {// balabala… …}}這樣就清晰多了 。
其中,最主要是要清楚幾種workQueue,也就是BlockingQueue<Runnable>的作用 。
SynchronousQueue同步隊列,這個隊列沒有所謂的緩沖,這樣做是為了排除阻塞時隊列丟消息的可能 。如果沒有其他微服務并行執行的話,可以放心地用這個隊列 , 不然還是小心一點為妙 。它的示例代碼:
/** * 同步隊列 */public class SynchronousQueueTest {public static void main(String[] args) {ExecutorService service = new ThreadPoolExecutor(1,// 當要處理的線程數超過maximumPoolSize時,拋出異常2,1000,TimeUnit.MILLISECONDS,new SynchronousQueue<Runnable>(),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());for (int i = 0; i < 10; i++) {service.execute(() ->System.out.println("當前線程 " + Thread.currentThread().getName()));}service.shutdown();}}ArrayBlockingQueue,它的使用范圍非常廣,一般可以用于輕量級的同步鎖 , 也就是在同一個服務中(也就是非微服務架構),如果要具有分布式鎖的功能又不想部署zookeeper這么麻煩的話,ArrayBlockingQueue就是一個非常不錯的選擇 。

推薦閱讀