定義理解
線程池其實是一種池化的技術實現,池化技術的核心思想就是實現資源的復用,避免資源的重復創建和銷毀帶來的性能開銷。線程池可以管理一堆線程,讓線程執行完任務之后不進行銷毀,而是繼續去處理其它線程已經提交的任務。
使用線程池的好處
- 降低資源消耗。通過重復利用已創建的線程降低線程創建和銷毀造成的消耗。
- 提高響應速度。當任務到達時,任務可以不需要等到線程創建就能立即執行。
- 提高線程的可管理性。線程是稀缺資源,如果無限制的創建,不僅會消耗系統資源,還會降低系統的穩定性,使用線程池可以進行統一的分配,調優和監控。
構造參數
- corePoolSize:線程池中用來工作的核心線程數量。
- maximumPoolSize:最大線程數,線程池允許創建的最大線程數。當線程池中的線程數達到corePoolSize后,如果任務隊列已滿,且需要繼續處理新任務,線程池會創建新線程(但總數不超過maximumPoolSize)來處理這些任務。(相當于排隊區滿了后,后來的線程可以直接插隊)如果任務數超過了maximumPoolSize,且任務隊列已滿,則線程池會根據拒絕策略來處理這些無法執行的任務。
- keepAliveTime:超出 corePoolSize 后創建的線程存活時間或者是所有線程最大存活時間,取決于配置。
- unit:keepAliveTime 的時間單位。
- workQueue:任務隊列,是一個阻塞隊列,當線程數達到核心線程數后,會將任務存儲在阻塞隊列中。常見實現:BlockingQueue接口的實現類,如ArrayBlockingQueue、LinkedBlockingQueue等。
- threadFactory :線程池內部創建線程所用的工廠。
- handler:拒絕策略;當隊列已滿并且線程數量達到最大線程數量時,會調用該方法處理任務。
如何設置參數
1. 確定核心線程數(corePoolSize)
- CPU密集型任務:對于CPU密集型任務,通常將核心線程數設置為CPU核心數的1到2倍之間。這可以確保充分利用CPU資源,同時避免過多的上下文切換。
- IO密集型任務:對于IO密集型任務,由于線程在等待IO操作時不會占用CPU,因此可以設置更多的核心線程數。一般來說,可以將核心線程數設置為CPU核心數的2倍以上,以便在等待IO時能夠處理更多的任務。
- 混合型任務:如果應用程序同時包含CPU密集型和IO密集型任務,則需要根據具體情況來平衡核心線程數的設置。
2. 確定最大線程數(maximumPoolSize)
- 資源受限的環境:在資源受限的環境中(如嵌入式系統或云服務器),需要限制最大線程數以防止過多線程占用資源。
- 高并發系統:對于需要處理大量并發請求的系統,可以適當增加最大線程數以提高系統的并發處理能力。但是,最大線程數的設置應該基于系統的負載能力和資源狀況進行綜合考慮。
3. 設置線程空閑時間(keepAliveTime)
- CPU密集型應用:對于CPU密集型應用,通常可以將線程空閑時間設置為較短的值,因為CPU資源非常寶貴,不希望有過多的空閑線程占用資源。在某些情況下,甚至可以將其設置為0,表示不保留非核心線程。
- IO密集型應用:對于IO密集型應用,由于線程在等待IO操作時不會占用CPU資源,因此可以將線程空閑時間設置為較長的值(如1分鐘以上),以避免線程頻繁啟動和銷毀造成的性能開銷。
4. 選擇任務隊列(workQueue)
- 有界隊列:使用有界隊列可以限制任務在隊列中的等待時間,避免因為任務過多而導致內存溢出。但是,如果隊列長度設置過小,可能會導致任務被拒絕。(一般選擇有界隊列)
- 無界隊列:使用無界隊列可以盡可能地緩存所有任務,但是需要注意內存消耗問題。如果使用了無界隊列,線程池的最大線程數參數可能會變得無效,因為線程池不會嘗試創建新線程來處理隊列中的任務。
5. 配置線程工廠(threadFactory)
線程工廠用于創建新線程。通過自定義線程工廠,可以設定線程的優先級、守護線程狀態等屬性,也可以為線程設置有意義的名字,便于在JVM中進行問題診斷。
6. 配置拒絕策略(handler)
當線程池無法處理新任務時(即線程數已達到maximumPoolSize,且任務隊列已滿),需要配置拒絕策略來處理這些無法執行的任務。常見的拒絕策略包括直接拋出異常、用調用者所在的線程來執行任務、忽略新任務以及拋棄隊列中最老的任務等。也可以根據需要自定義拒絕策略。