使用線程池的好處
- 降低資源消耗。通過重複利用已創建的線程降低線程創建和銷燬造成的消耗。
- 提高響應速度。當任務到達時,任務可以不需要的等到線程創建就能立即執行。
- 提高線程的可管理性。線程是稀缺資源,如果無限制的創建,不僅會消耗系統資源,還會降低系統的穩定性,使用線程池可以進行統一的分配,調優和監控。
Executor 框架結構
1) 任務(Runnable
/Callable
)
執行任務需要實現的 Runnable
接口 或 Callable
接口。Runnable
接口或 Callable
接口 實現類都可以被 ThreadPoolExecutor
或 ScheduledThreadPoolExecutor
執行
2) 任務的執行(Executor
)
3) 異步計算的結果(Future
)
當我們把 Runnable
接口 或 Callable
接口 的實現類提交給 ThreadPoolExecutor
或 ScheduledThreadPoolExecutor
執行。(調用 submit()
方法時會返回一個 FutureTask
對象)
ThreadPoolExecutor
corePoolSize
: 核心線程數線程數定義了最小可以同時運行的線程數量。maximumPoolSize
: 當隊列中存放的任務達到隊列容量的時候,當前可以同時運行的線程數量變爲最大線程數。workQueue
: 當新任務來的時候會先判斷當前運行的線程數量是否達到核心線程數,如果達到的話,信任就會被存放在隊列中。
execute()
vs submit()
execute()
方法用於提交不需要返回值的任務,所以無法判斷任務是否被線程池執行成功與否;submit()
方法用於提交需要返回值的任務。線程池會返回一個Future
類型的對象,通過這個Future
對象可以判斷任務是否執行成功
線程池大小確定
- CPU 密集型任務(N+1): 這種任務消耗的主要是 CPU 資源,可以將線程數設置爲 N(CPU 核心數)+1,比 CPU 核心數多出來的一個線程是爲了防止線程偶發的缺頁中斷,或者其它原因導致的任務暫停而帶來的影響。一旦任務暫停,CPU 就會處於空閒狀態,而在這種情況下多出來的一個線程就可以充分利用 CPU 的空閒時間。
- I/O 密集型任務(2N): 這種任務應用起來,系統會用大部分的時間來處理 I/O 交互,而線程在處理 I/O 的時間段內不會佔用 CPU 來處理,這時就可以將 CPU 交出給其它線程使用。因此在 I/O 密集型任務的應用中,我們可以多配置一些線程,具體的計算方法是 2N。