Java 併發之線程池學習

建立

經過ThreadPoolExecutor來建立一個線程池java

new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
keepAliveTime, milliseconds,runnableTaskQueue, threadFactory,handler);

參數說明:git

  • corePoolSize 線程池中任務的基本個數
    • 新提交一個任務時,若線程池中個數未達到基本個數,則新建一個線程
    • 到線程池中的線程數達到基本個數時,再提交任務,則看是否有空閒線程,有則只直接使用
    • 若無空閒線程,則新幾條的任務放入排隊
  • maximumPoolSize 線程chi池中任務的作多個數
    • 當線程池中個數達到 corePoolSize & 且隊列排滿了
    • 新建立線程來執行任務
    • 當線程池中任務達到maximumPoolSize,則再也不建立
  • keepAliveTime 線程池的工做線程空閒後存活的時間
  • milliseconds 配合上個參數使用,表示時間的單位,如TimeUnit.SECONDS
  • runnableTaskQueue 排隊隊列
    • ArrayBlockingQueue基於數組結構的有界阻塞隊列,此隊列按 FIFO(先進先出)原則對元素進行排序
    • LinkedBlockingQueue 基於鏈表結構的阻塞隊列,此隊列按FIFO (先進先出) 排序元素,吞吐量一般要高於ArrayBlockingQueue
    • SynchronousQueue 一個不存儲元素的阻塞隊列。每一個插入操做必須等到另外一個線程調用移除操做,不然插入操做一直處於阻塞狀態,吞吐量一般要高於LinkedBlockingQueue
    • PriorityBlockingQueue 一個具備優先級得無限阻塞隊列
  • threadFactory 建立線程的工廠,一般會從新指定線程名,方便debug
  • handler 線程池飽和策略
    • 當線程數達到 maximumPoolsize 隊列已滿時,表示飽和
    • CallerRunsPolicy 只用調用者所在線程來運行任務
    • DiscardOldestPolicy 丟棄隊列裏最近的一個任務,並執行當前任務
    • DiscardPolicy 不處理,丟棄掉
    • AbortPolicy 拋異常
    • 也能夠根據應用場景須要來實現RejectedExecutionHandler接口自定義策略

線程池提交任務的處理流程數據庫

線程池提交任務的處理流程

提交任務

1. execute(Runnable)

直接執行一個實現了Runnable的接口,即表示提交了一個異步任務給線程池數組

2. submit(Runnable)

相比較於上面的,區別是這個會返回一個 Future<V> 對象,經過調用future.get() 能夠獲取線程的返回值,其中這個方程是線程阻塞的,直到返回告終果以後,纔會繼續執行下去微信

關閉線程

線程池的shutdown或shutdownNow方法來關閉線程池框架

shutdown的原理是隻是將線程池的狀態設置成SHUTDOWN狀態,而後中斷全部沒有正在執行任務的線程異步

shutdownNow的原理是遍歷線程池中的工做線程,而後逐個調用線程的interrupt方法來中斷線程,因此沒法響應中斷的任務可能永遠沒法終止ui

調用了這兩個關閉方法的其中一個,isShutdown方法就會返回true。當全部的任務都已關閉後,才表示線程池關閉成功,這時調用isTerminaed方法會返回true。.net

至於咱們應該調用哪種方法來關閉線程池,應該由提交到線程池的任務特性決定,一般調用shutdown來關閉線程池,若是任務不必定要執行完,則能夠調用shutdownNow線程

線程池的配置

分析

  1. 任務的性質:CPU密集型任務,IO密集型任務和混合型任務。
    • CPU密集型任務配置儘量少的線程數量,如配置Ncpu+1個線程的線程池
    • IO密集型任務則因爲須要等待IO操做,線程並非一直在執行任務,則配置儘量多的線程,如2*Ncpu
    • 混合型的任務,若是能夠拆分,則將其拆分紅一個CPU密集型任務和一個IO密集型任務,只要這兩個任務執行的時間相差不是太大,那麼分解後執行的吞吐率要高於串行執行的吞吐率,若是這兩個任務執行時間相差太大,則不必進行分解
  2. 任務的優先級:高,中和低。
    • 優先級不一樣的任務可使用優先級隊列PriorityBlockingQueue來處理
  3. 任務的執行時間:長,中和短。
    • 執行時間不一樣的任務能夠交給不一樣規模的線程池來處理,或者也可使用優先級隊列,讓執行時間短的任務先執行
  4. 任務的依賴性:是否依賴其餘系統資源,如數據庫鏈接。
    • 由於線程提交SQL後須要等待數據庫返回結果,若是等待的時間越長CPU空閒時間就越長,那麼線程數應該設置越大,這樣才能更好的利用CPU

獲取線程數

Runtime.getRuntime().availableProcessors()

實例分析

背景:

實現一個異步的報警case,首先是有三種報警方式,郵件、微信、短信;其次是具體的報警都是異步處理(一個報警執行的線程池);要求一分鐘內報警有上限設置(即要實現報警的計數與清零);報警的重要性根據郵件-》微信-》短信進行遞增,當超過每一個報警類型的最低閥值時,晉升報警類型

silver-alarm 一個報警的基本框架

源碼傳送門

相關文章
相關標籤/搜索