總結
根據“任務的性質”分析
CPU 密集型任務
- 和內存打交道,大量計算。例如大數的計算,正則匹配
- 如何配置:
- CPU 密集型任務應配置盡可能小的線程,如配置 Ncpu+1 個線程的線程池(Ncpu 是處理器的核的數目),這樣留一個空出來,用來做切換。。
- 如果線程太多,會造成線程在CPU內部的上下文切換。。CPU的線程上下文切換比指令執行耗時的更多。
IO 密集型任務
- 解釋:和磁盤,網絡,文件,數據庫交互很多的。
- 如何配置:由於 IO 密集型任務線程並不是一直在執行任務,在操作的時間,是不消耗CPU的。不會經常在CPU內切換線程上下文,則應配置盡可能多的線程,如 2*Ncpu。
-
對於 IO 型的任務的最佳線程數,有個公式可以計算 Nthreads = NCPU * UCPU * (1 + W/C)
❑NCPU 是處理器的核的數目❑UCPU 是期望的 CPU 利用率(該值應該介於 0 和 1 之間)
❑W/C 是等待時間與計算時間的比率。等待時間與計算時間我們在 Linux 下使用相關的 vmstat 命令或者 top 命令查看。
-
混合型任務
- 解釋:前兩者的混合
- 如何配置:如果可以拆分,將其拆分成一個 CPU 密集型任務和一個 IO 密集型任務。
- 只要這兩個任務執行的時間相差不是太大,那么分解后執行的吞吐 量將高於串行執行的吞吐量。
- 如果這兩個任務執行時間相差太大(例如:一個是常量時間,一個是正無窮),則沒必要進行分解。
- 可以通過 Runtime.getRuntime().availableProcessors()方法獲得當前設備的 CPU 個數。
根據“任務的優先級”分析
優先級不同的任務可以使用優先級隊列 PriorityBlockingQueue 來處理。它可 以讓優先級高的任務先執行。
根據“任務的執行時間”分析
執行時間不同的任務可以交給不同規模的線程池來處理,或者可以使用優先 級隊列,讓執行時間短的任務先執行。
根據“任務的依賴性(依賴數據庫連接)”分析
依賴數據庫連接池的任務,因為線程交 SQL 后需要等待數據庫返回結果, 等待的時間越長,則 CPU 空閑時間就越長,那么線程數應該設置得越大,這樣 才能更好地利用 CPU。
建議使用有界隊列
有界隊列能增加系統的穩定性和預警能力,可以根據需 要設大一點兒,比如幾千。
假設,我們現在有一個 Web 系統,里面使用了線程池來處理業務,在某些 情況下,系統里后台任務線程池的隊列和線程池全滿了,不斷拋出拋棄任務的異 常,通過排查發現是數據庫出現了問題,導致執行 SQL 變得非常緩慢,因為后台 任務線程池里的任務全是需要向數據庫查詢和插入數據的,所以導致線程池里的 工作線程全部阻塞,任務積壓在線程池里。
如果當時我們設置成無界隊列,那么線程池的隊列就會越來越多,有可能會 撐滿內存,導致整個系統不可用,而不只是后台任務出現問題。