Java Concurrency: Worker Thread,執行緒池的基本模式

Charlie Lee
Bucketing
Published in
Dec 4, 2020

Worker Thread執行緒池的基本模式,但是你有想過為何要使用它嗎?

Photo by Christopher Burns on Unsplash

前言

在開始前先回顧Thread-Per-Message模式運行的方法,當接收到任務後馬上創建一個匿名執行緒,讓此直行緒處理任務,任務處理完後任由Java GC(垃圾回收)機制處置,這樣的模式當任務數量不多時可以非常簡單直覺有效率的運轉,可是當任務數量上升,CPU的使用率和記憶體就有可能會爆炸。因為每次創建執行緒作業系統都需要fork一次main thread導致記憶體不斷複製,而且Thread數量多的話CPU也需要高頻率的切換不同Thread執行,不但沒有享受到Multi Thread的高效而且還可能導致系統崩潰(OOM)。

此時就進入到今天的主題Worker Thread,Worker Thread就是用來解決上述問題的方法,也是執行池的基本,Worker Thread的關鍵非常簡單,就是控制創建的Thread數量與重複使用。

Worker Thread & Thread-Per-Message

如上篇所提Thread-Per-Message的運作如下,每當有任務時Main就new Thread出來執行

這樣的運作模式在輕量級的系統運作完全沒有問題,而且非常好開發,但如果Thread要執行的邏輯變複雜,而且需求越來越多的話就會非常恐怖,CPU需要高頻的切換不同的Thread Context執行內容,本來3秒可以結束的任務,因為CPU高頻率的切換永源無法結束。

本來單純的以為不斷的生成Thread就可以平行處理,沒想到反而應此造成系統緩慢與崩潰,而為了解決這問題Worker Thread模式就誕生了。

Worker Thread與Thread-Per-Message打個比方,Thread-Per-Message就像是打雜工,在網路上PO個訊息隨便一個人就可以開始工作,但是真實在工作時因為每個人都是第一次合作,要不斷不斷的磨合浪費彼此的時間,而Worker Thread就如同,受夠了雜工自己開公司建立工作室,每個員工都互相有默契並且有效率。

Worker Thread的執行如下圖,創造固定數量的Thread並且為這些Thread建立任務柱列(Queue),當有任務來時馬上就處理,如果沒有的話就等待任務的到來

Worker Thread範例程式碼

上方範例程式碼,將管理WorkerThread的物件命名為Pool(其實就是之前文章常提到的執行緒池),在其中TaskQueue使用線程安全的LinkedBlockingQueue,每當Queue為空則會block住避免while(true)自迴圈持續的消耗CPU時間,而在使用方面創立了submit方法,要使用時只需將實作Runnable的Task丟進來就會開始處理。

Github原始碼

結論

此篇文章介紹了Worker Thread,並且還有提及Worker Thread改善Thread-Per-Message的地方,主要改善在於

  1. 限制Thread的數量 — 在Multi Thread中不是Thread越多越有效率
  2. 重複使用Thread — OS就不需要每次new就複製Thread的記憶體
  3. 雜工變成工作室的概念

下一篇文章會提及,Producer & Consumer如何解偶Thread的執行邏輯,並且提升Thread的

--

--