Java線程池管理最佳實踐(設計模式)

引言

在多線程編程中,線程池是一種非常重要的資源管理工具。合理使用線程池可以顯著提高系統性能,避免頻繁創建和銷毀線程帶來的開銷。今天,我將為大家深入分析一個實用的ThreadPoolManager實現,它來自com.kingdee.eas.util包,是一個優秀的線程池管理工具類。

核心設計解析

1. 單例模式實現

private static final ThreadPoolManager INSTANCE = new ThreadPoolManager();public static ThreadPoolManager getInstance() {return INSTANCE;
}

ThreadPoolManager采用餓漢式單例模式,確保全局只有一個線程池實例。這種設計避免了重復創建線程池帶來的資源浪費,也便于統一管理。

2. 自動計算線程池大小

static {int cpus = Runtime.getRuntime().availableProcessors();if (cpus <= 0) {logger.error("無法獲取 CPU 核心數,默認使用 2");cpus = 2;}AVAILABLE_PROCESSORS = cpus;
}private ThreadPoolManager() {int poolSize = AVAILABLE_PROCESSORS * 2;poolSize = Math.max(2, poolSize); // 至少保留 2個線程this.executor = Executors.newFixedThreadPool(poolSize);registerShutdownHook();
}

這段代碼展示了幾個優秀實踐:

  1. 根據CPU核心數動態計算線程池大小(核心數×2)

  2. 設置最小線程數為2,確保低配機器也能運行

  3. 使用靜態初始化塊預先計算CPU核心數,避免重復計算

3. 優雅的關閉機制

private void registerShutdownHook() {Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {@Overridepublic void run() {logger.error("【Shutdown Hook】開始關閉線程池...");ThreadPoolManager.this.shutdown();logger.error("【Shutdown Hook】線程池已關閉");}}));
}public void shutdown() {if (!executor.isShutdown()) {executor.shutdown(); // 不再接受新任務try {if (!executor.awaitTermination(800, java.util.concurrent.TimeUnit.MILLISECONDS)) {logger.error("線程池未完全關閉,嘗試強制關閉...");executor.shutdownNow();}} catch (InterruptedException e) {executor.shutdownNow();Thread.currentThread().interrupt();}}
}

關閉機制的設計亮點:

  1. 注冊JVM關閉鉤子,確保應用退出時自動關閉線程池

  2. 分階段關閉:先嘗試優雅關閉,超時后強制關閉

  3. 正確處理中斷異常,恢復中斷狀態

使用示例

使用這個線程池管理器非常簡單:

// 提交任務
ThreadPoolManager.getInstance().submit(() -> {// 你的任務代碼
});// 手動關閉(通常不需要,因為有shutdown hook)
// ThreadPoolManager.getInstance().shutdown();

最佳實踐建議

  1. 任務設計:確保提交的任務是線程安全的,避免共享可變狀態

  2. 異常處理:在任務內部處理好異常,避免任務因異常而終止

  3. 監控:可以擴展此類,添加監控線程池狀態的功能

  4. 動態調整:對于更復雜的場景,可以考慮使用ThreadPoolExecutor直接創建線程池,以便動態調整參數

可能的改進方向

  1. 配置化:將線程池大小等參數改為可配置的,而不是硬編碼

  2. 多樣化線程池:支持創建不同類型的線程池(如緩存線程池、定時線程池等)

  3. 監控擴展:添加線程池狀態監控和報警功能

  4. 任務隊列限制:固定線程池默認使用無界隊列,可以考慮改為有界隊列避免OOM

總結

這個ThreadPoolManager實現簡潔而實用,涵蓋了線程池管理的核心關注點:初始化、任務提交和優雅關閉。特別適合作為中小型應用的默認線程池管理方案。通過學習這個實現,我們可以深入理解Java線程池的最佳實踐。

完整代碼

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;import org.apache.log4j.Logger;public class ThreadPoolManager {private static final Logger logger = Logger.getLogger("com.kingdee.eas.util.ThreadPoolManager");private static final ThreadPoolManager INSTANCE = new ThreadPoolManager();private final ExecutorService executor;private static final int AVAILABLE_PROCESSORS;static {int cpus = Runtime.getRuntime().availableProcessors();if (cpus <= 0) {logger.error("無法獲取 CPU 核心數,默認使用 2");cpus = 2;}AVAILABLE_PROCESSORS = cpus;}// 私有構造函數private ThreadPoolManager() {// 根據當前CPU核心數,創建合適的核心線程數int poolSize = AVAILABLE_PROCESSORS * 2;poolSize = Math.max(2, poolSize); // 至少保留 2個線程this.executor = Executors.newFixedThreadPool(poolSize);registerShutdownHook();}public static ThreadPoolManager getInstance() {return INSTANCE;}public void submit(Runnable task) {executor.submit(task);}// 注冊 JVM 關閉鉤子,private void registerShutdownHook() {Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {@Overridepublic void run() {logger.error("【Shutdown Hook】開始關閉線程池...");ThreadPoolManager.this.shutdown(); // 調用關閉方法logger.error("【Shutdown Hook】線程池已關閉");}}));}/*** 關閉線程池(建議在應用退出前調用)*/public void shutdown() {if (!executor.isShutdown()) {executor.shutdown(); // 不再接受新任務try {// 最多等待一段時間讓任務完成if (!executor.awaitTermination(800, java.util.concurrent.TimeUnit.MILLISECONDS)) {logger.error("線程池未完全關閉,嘗試強制關閉...");// 強制中斷正在執行的任務executor.shutdownNow();}} catch (InterruptedException e) {// 被中斷時恢復中斷狀態executor.shutdownNow();Thread.currentThread().interrupt();}}}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/907278.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/907278.shtml
英文地址,請注明出處:http://en.pswp.cn/news/907278.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

4.8.2 利用Spark SQL計算總分與平均分

在本次實戰中&#xff0c;我們的目標是利用Spark SQL計算學生的總分與平均分。首先&#xff0c;我們準備了包含學生成績的數據文件&#xff0c;并將其上傳至HDFS。接著&#xff0c;通過Spark的交互式編程環境&#xff0c;我們讀取了成績文件并將其轉換為結構化的DataFrame。然后…

HTML 文件路徑完全指南:相對路徑、絕對路徑解析與引用技巧

一、為什么必須學會文件路徑&#xff1f;—— 網頁引用資源的 “地址規則” 在 HTML 中&#xff0c;引用圖片、CSS、JS 等外部文件時&#xff0c;必須通過文件路徑告訴瀏覽器資源的位置。路徑錯誤會導致資源無法加載&#xff08;頁面出現 broken image 圖標或樣式丟失&#xf…

keepalived兩臺設備同時出現VIP問題

目錄 問題背景&#xff1a; 日志分析如下&#xff1a; 原因和解決方案總結&#xff1a; 問題背景&#xff1a; keepalived-master和keepalived-slave同時出現了VIP&#xff0c;出現了非對稱路由和雙主現象 日志分析如下&#xff1a; master能夠接受到來自slave的通告消息…

【開源解析】基于PyQt5+Folium的谷歌地圖應用開發:從入門到實戰

&#x1f310;【開源解析】基于PyQt5Folium的谷歌地圖應用開發&#xff1a;從入門到實戰 &#x1f308; 個人主頁&#xff1a;創客白澤 - CSDN博客 &#x1f525; 系列專欄&#xff1a;&#x1f40d;《Python開源項目實戰》 &#x1f4a1; 熱愛不止于代碼&#xff0c;熱情源自每…

篇章五 數據結構——鏈表(一)

目錄 1.ArrayList的缺陷 2. 鏈表 2.1 鏈表的概念及結構 2.2 鏈表結構 1. 單向或者雙向 2.帶頭或者不帶頭 3.循環或者非循環 2.3 鏈表的實現 1.完整代碼 2.圖解 3.顯示方法 4.鏈表大小 5. 鏈表是否存在 key 值 6.頭插法 7.尾插法 8.中間插入 9.刪除key值節點 10.…

數據庫相關面試

數據庫相關面試 Mysql MySQL中的事務隔離級別及其特點 參考&#xff1a;事務的隔離級別&#xff1a;可重復讀 未提交讀(Read Uncommitted)&#xff1a;允許臟讀&#xff0c;也就是可能讀取到其他會話中未提交事務修改的數據 已提交讀(Read Committed)&#xff1a;只能讀取到…

基于Scrapy的天貓商品數據爬取與分析實戰(含API簽名破解與可視化)

基于Scrapy的天貓商品數據爬取與分析實戰&#xff08;含API簽名破解與可視化&#xff09; 本文以華為Mate 60 Pro為例&#xff0c;詳細介紹如何使用Scrapy框架爬取天貓商品數據&#xff0c;涵蓋API簽名破解、反爬應對、數據存儲及可視化全流程&#xff0c;適合爬蟲進階學習者實…

【C++進階篇】哈希表的模擬實現(賦源碼)

這里寫目錄標題 前言一. 開放地址法實現哈希表1.1 閉散列結構定義1.2 構造函數1.3 插入&#xff08;線性探測&#xff09;1.3.1 傳統寫法1.3.2 現代寫法 1.4 查找1.5 刪除 二. 鏈地址法實現哈希表&#xff08;哈希桶&#xff09;2.1 開散列結構定義2.2 構造函數2.3 插入2.4 查找…

07-后端Web實戰(部門管理)

5. 修改部門 對于任何業務的修改功能來說&#xff0c;一般都會分為兩步進行&#xff1a;查詢回顯、修改數據。 5.1 查詢回顯 5.1.1 需求 當我們點擊 "編輯" 的時候&#xff0c;需要根據ID查詢部門數據&#xff0c;然后用于頁面回顯展示。 5.1.2 接口描述 參照參照…

深度解析項目集方向或目標根本性轉變的應對策略 —— 項目集管理實戰指南

在復雜多變的商業環境中&#xff0c;項目集管理面臨著重重挑戰&#xff0c;而項目集方向或目標的根本性轉變無疑是其中最具沖擊力的問題之一。本文將深度剖析這一難題&#xff0c;為項目集管理從業者提供實用、新穎且富有價值的應對策略&#xff0c;助力大家在項目集管理的復雜…

JAVA面試復習知識點

面試中遇到的題目&#xff0c;記錄復習&#xff08;持續更新&#xff09; Java基礎 1.String的最大長度 https://www.cnblogs.com/wupeixuan/p/12187756.html 2.集合 Collection接口的實現&#xff1a; List接口&#xff1a;ArraryList、LinkedList、Vector Set接口&#xff1a…

【燒腦算法】定長滑動窗口:算法題中的“窗口”智慧

目錄 引言 定長滑動窗口習題剖析 3439. 重新安排會議得到最多空余時間 I 2134. 最少交換次數來組合所有的 1 II 1297. 子串的最大出現次數 2653. 滑動子數組的美麗值 567. 字符串的排列 438. 找到字符串中所有字母異位詞 30. 串聯所有單詞的子串 220. 存在重復元素 II…

JWT安全:接收無簽名令牌.【簽名算法設置為none繞過驗證】

JWT安全&#xff1a;假密鑰【簽名隨便寫實現越權繞過.】 JSON Web 令牌 (JWT)是一種在系統之間發送加密簽名 JSON 數據的標準化格式。理論上&#xff0c;它們可以包含任何類型的數據&#xff0c;但最常用于在身份驗證、會話處理和訪問控制機制中發送有關用戶的信息(“聲明”)。…

XGBoost與SHAP深度解析:從算法原理到實戰價值

在機器學習領域&#xff0c;XGBoost以其卓越的性能長期占據Kaggle競賽和工業界的主流地位&#xff0c;而SHAP&#xff08;SHapley Additive exPlanations&#xff09;則成為模型可解釋性的標桿工具。本文將深度解析兩者的技術內核&#xff0c;并通過實戰案例揭示其結合應用的實…

Java SE Cloneable接口和深/淺拷貝

Java為我們提供了各種各樣功能的接口&#xff0c;Clonable接口就是其中之一。 它通常配合Object類的 clone方法使用。這個方法可以為我們創建一個對象的拷貝&#xff0c;即復制一個對象。在進入本文的主要內容之前&#xff0c;先來對訪問限定符 protected進行一個解剖。 1.再…

Python學習(3) ----- Python的函數定義及其使用

Python 中函數是組織好的、可重復使用的代碼塊&#xff0c;用于實現單一或相關聯的功能。下面是函數定義和使用的完整說明&#xff1a; &#x1f4cc; 一、函數定義語法 def 函數名(參數1, 參數2默認值, *args, **kwargs):"""函數說明文檔"""函…

vue2使用el-tree實現兩棵樹間節點的拖拽復制

原文鏈接&#xff1a;兩棵el-tree的節點跨樹拖拽實現 參照這篇文章&#xff0c;把它做成組件&#xff0c;新增左側樹&#xff08;可拖出&#xff09;被拖節點變灰提示&#xff1b; 拖拽中&#xff1a; 拖拽后&#xff1a; TreeDragComponent.vue <template><!-- …

智變與重構:AI 賦能基礎教育教學的范式轉型研究報告

一、研究背景與核心價值 &#xff08;一&#xff09;技術驅動下的教育轉型浪潮 在全球數字化轉型加速的背景下&#xff0c;人工智能作為核心技術力量&#xff0c;正重塑基礎教育生態。據《人工智能賦能未來教育研究報告》指出&#xff0c;我國教育數字化戰略行動已推動超 70…

Go語言中Print、Printf和Println的區別及使用場景詳解

在Go語言的fmt包中&#xff0c;Print、Printf和Println是三個基礎但功能各異的輸出函數。本文將從多個維度進行詳細對比分析&#xff0c;并給出具體的使用建議。 1. 核心區別深度解析 1.1. 函數簽名與基本行為 func Print(a ...interface{}) (n int, err error) func Printf…

高端制造行業 VMware 替代案例合集:10+ 頭部新能源、汽車、半導體制造商以國產虛擬化支持 MES、PLM 等核心應用系統

在“中國制造 2025”政策的推動下&#xff0c;國內的新能源、汽車制造、半導體、高端裝備等高端制造產業迎來了蓬勃發展&#xff0c;成為全球制造業版圖中舉足輕重的力量。訂單數量的激增與國產化轉型的趨勢&#xff0c;也為高端制造企業的 IT 基礎設施帶來了新的挑戰&#xff…