執行緒池:Executor框架
阿新 • • 發佈:2018-12-24
無限制建立執行緒的不足
- 執行緒生命週期的開銷非常高。執行緒的建立並不是沒有代價的。根據平臺的不同,實際的開銷也有所不同,但是執行緒的建立過程都會需要時間,延遲處理的請求,並且需要JVM和作業系統提供一些輔導操作。如果請求的到達率非常高且請求的處理過程是輕量級的,例如大多數伺服器應用程式就是這種情況,那麼為每個請求建立一個新執行緒將消耗大量的計算資源。
- 資源消耗。活躍的執行緒會消耗資源,尤其是記憶體。如果可執行的執行緒數量多於可用處理器的數量,那麼有些執行緒將會閒置。大量的空閒的執行緒會佔用許多記憶體,給垃圾回收器帶來壓力,而且大量執行緒在競爭CPU資源時還將產生其他的效能開銷。如果你已經擁有足夠多的執行緒使所有cpu保持忙碌狀態,那麼再建立更多的執行緒反而會降低效能。
- 穩定性。在可建立執行緒的數量上存在一個限制。這個限制將隨著平臺的不同而不同,並且受多個因素制約,包括jvm的啟動引數、Thread建構函式中請求的棧大小,以及底層操作的限制等。如果破壞這些限制,那麼很可能丟擲OutOfMemoryError異常,要想從這種錯誤中恢復過來是非常危險的,更簡單的辦法是通過構造程式來避免超出這種限制。
以上摘抄自《JAVA併發程式設計實戰》
由以上問題看出,無限建立執行緒的危害,在jdk5以後提供Executor框架有效的為使用者提供了一個可用的方案
- Executor基於生產者-消費者模式,提交任務相當於生產者(生成待完成的工作單元),執行任務的執行緒則相當於消費者(執行這些工作單元)。
- 簡單使用:
列印結果列印100次,執行順序也不是按照順序執行,說明是單獨執行緒每個執行的且執行100次/** * 執行緒池測試 */ public class ThreadPoolExecutorTest { private static final Executor executor = Executors.newFixedThreadPool(10); /** * 執行緒池 * * @param args */ public static void main(String[] args) { for (int i = 0; i <= 100; i++) { int finalI = i; executor.execute(() -> System.out.println("執行執行緒" + finalI)); } } }
- Executors工具類原始碼可以建立多種執行緒池,這裡主要和策略有關係(new的方式建立對應執行緒池也可以設定策略)原始碼比較多請參考:Executors建立的4種執行緒池的使用
執行緒池主要是通過狀態引數進行控制的,任務執行其實也是佇列的一種實現。有興趣的可以參考部落格看一看雨原始碼:JDK執行緒池原始碼分析之ThreadPoolExecutor,我覺得講的還是比較通俗易懂
到這裡我就想到Spring task定時任務了,所以專門百度了一下,然後順帶看了一點原始碼,大概囉嗦一下
-
Spring在任務排程時預設使用的還是ScheduledThreadPoolExecutor可以檢視部分原始碼ThreadPoolTaskScheduler類:
@UsesJava7 @Override protected ExecutorService initializeExecutor( ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) { this.scheduledExecutor = createExecutor(this.poolSize, threadFactory, rejectedExecutionHandler); if (this.removeOnCancelPolicy) { if (setRemoveOnCancelPolicyAvailable && this.scheduledExecutor instanceof ScheduledThreadPoolExecutor) { ((ScheduledThreadPoolExecutor) this.scheduledExecutor).setRemoveOnCancelPolicy(true); } else { logger.info("Could not apply remove-on-cancel policy - not a Java 7+ ScheduledThreadPoolExecutor"); } } return this.scheduledExecutor; }
-
Spring在使用task排程時每個任務預設是單執行緒跑的,需要單獨設定執行緒池具體設定方式參考:Spring Boot 定時任務單執行緒和多執行緒,spring task定時器的配置使用
最後吐槽一波,翻了好久,Spring task原始碼讀著還是很吃力的,希望自己能多提升一點能力吧。另外沒有詳細介紹執行緒池,是因為我覺得分享的部落格已經講得非常到位了,我也沒必要去copy,見諒吧。