下圖為線程池的構造方法,我們可以自定義一些功能實現項目優化
1、預先啟動核心線程
this.prestartAllCoreThreads();
使用方式:自定義線程池的構造方法中調用
作用:當真正任務被執行時,可以減少創建線程帶來的性能損耗
2、自定義線程池線程工廠
官方提供的默認線程池工廠為Executors.defaultThreadFactory();
我們可以仿照進行自定義擴展線程工廠,增加一些個性化功能。
如下圖所示,我們自定義線程池線程工廠時可以附加很多功能。
1、定制化線程池內線程名稱,便於我們在線上快速定位;
2、在創建線程時,設置其是否為守護線程 等等
3、感知並捕獲任務異常
線程池執行任務時(執行execute方法時),當任務拋出異常,線程池並沒有捕獲,因此直接導致任務失敗,線程池線程銷毀【往期文章:線程池原理】。
工作中往往因為信息的缺失,出現問題卻感知不到而導致線上事故,帶來損失
通過實現Thread的UncaughtExceptionHandler接口,為線程池線程設置異常處理類,從而達到任務異常感知和捕獲
4、線程池監控和告警
線程池執行任務,對我們而言是一個黑盒。
任務有可能直接被執行;也可能暫存到隊列,長時間無法被執行導致系統性能降低;又或者任務被丟棄,以及被丟棄的數量。
因為這些不確定,在系統性能被影響時,無法采取合理的方式進行調整。
以下幾個自定義功能,可以讓我們對其進行宏觀的監控
4.1、使用輪詢獲取線程池內狀態信息(不推薦)
線程池提供很多get方法獲取線程池內實時信息,但大部分都是加鎖操作,頻繁使用會降低線程池處理任務的效率。
因此這種方式並不推薦。
4.2、根據線程池本身提供的鈎子,進行自定義擴展
4.2.1、執行每個任務的監控
線程池線程通過runWorker方法執行每個任務時,前后都提供了空方法,供自定義擴展。
執行任務前方法:beforeExecute(wt, task);
執行任務:task.run();
執行任務后方法:afterExecute(task, thrown);
以下為自定義擴展的例子:
beforeExecute(wt, task);方法擴展
afterExecute(task, thrown);方法擴展
通過自定義beforeExecute和afterExecute方法,可以監控到任務執行耗時、可用率、執行次數等信息
4.2.2、被拒絕的任務的監控
當任務被拒絕時,可以自定義CallerRunsPolicy拒絕策略來監控相關信息
以下為自定義擴展的例子
通過自定義CallerRunsPolicy拒絕策略,可以監控被拒絕任務的執行耗時、可用率、執行次數等信息
以上的可擴展的方法可以抽象出來,面向接口編程
通過責任鏈模式處理多種業務
5、線程池參數動態修改
使用zookeeper動態修改線程池參數
5.1、線程池提供了線程數、空閑時間等信息的set方法
5.2、自定義可修改大小的隊列
修改隊列的方式可以查看上期文章:動態修改線程池隊列大小
6、自定義關閉線程池
RunTime.getRunTime().addShutdownHook的作用就是在JVM銷毀前執行的一個線程
7、感知FutureTask任務的結束
任務進入最終態(任務執行完成、異常、取消、打斷)時,調用unpark方法恢復因調用get()方法而掛起的線程,並調用done擴展空方法
futureTask任務結束后,會調用done空方法
執行多個任務時,通過任務執行done方法的先后順序,可以感知任務執行完成的先后順序
使用場景:
1、批量任務處理,哪個任務的done方法先被調用,可以優先執行哪個任務。提高任務的處理速度
2、線上提交訂單時,往往需要同時消費多個資源。但只要有一個資源消費失敗,所有資源都是要回滾的。
因此可以通過done方法快速感知處理快的任務。提前感知到消費失敗的情況並做回滾。從而提高效率
3、官方提供了一些done方法的功能
比如:ExecutorCompletionService將任務按照完成的先后順序,存儲到隊列中。並以此獲取處理
8、總結
1、通過閱讀源碼,可以讓我們找到很多可擴展的方法,供我們自定義功能
2、查看可擴展方法的具體實現,就可以找到官方提供的一些擴展實現,學習其中的使用
------The End------
如果這個辦法對您有用,或者您希望持續關注,也可以掃描下方二維碼或者在微信公眾號中搜索【碼路無涯】