Java多線程實現之線程池詳解
- 一、線程池的基本概念
- 1.1 為什么需要線程池
- 1.2 線程池的核心思想
- 二、Java線程池的實現
- 2.1 Executor框架
- 2.2 ThreadPoolExecutor構造參數
- 三、常見線程池類型
- 3.1 FixedThreadPool
- 3.2 CachedThreadPool
- 3.3 SingleThreadExecutor
- 3.4 ScheduledThreadPool
- 四、線程池的工作流程
- 五、線程池的使用示例
- 5.1 提交Runnable任務
- 5.2 提交Callable任務
- 5.3 定時任務
- 六、線程池的拒絕策略
- 6.1 AbortPolicy(默認)
- 6.2 CallerRunsPolicy
- 6.3 DiscardPolicy
- 6.4 DiscardOldestPolicy
- 七、線程池的監控與調優
- 7.1 監控線程池狀態
- 7.2 合理配置線程池大小
- 八、線程池的最佳實踐
- 8.1 避免使用Executors工廠方法
- 8.2 正確關閉線程池
- 8.3 使用自定義線程工廠
線程池在Java中是一種重要工具,用于管理和復用線程資源,合理使用線程池可以提高程序性能、減少資源消耗,并簡化線程管理。本文我將詳細介紹Java線程池的實現原理、常見類型以及使用方法等等,幫你更好地理解和深入Java的多線程實現。
一、線程池的基本概念
1.1 為什么需要線程池
- 線程創建和銷毀開銷大:頻繁創建和銷毀線程會消耗大量系統資源
- 資源管理困難:無限制創建線程可能導致系統資源耗盡
- 控制并發度:線程池可以限制同時運行的線程數量,避免過度并發
1.2 線程池的核心思想
線程池預先創建一定數量的線程,當有任務提交時,從線程池中獲取線程執行任務,任務執行完畢后線程不會銷毀,而是返回線程池等待下一個任務。
二、Java線程池的實現
2.1 Executor框架
Java通過Executor
框架提供線程池的實現,核心接口和類如下:
- Executor:線程池的基礎接口,定義了執行任務的方法
- ExecutorService:擴展了
Executor
,提供了管理線程池的方法 - ThreadPoolExecutor:線程池的核心實現類
- ScheduledExecutorService:支持定時任務的線程池接口
- Executors:工具類,提供創建線程池的靜態工廠方法
2.2 ThreadPoolExecutor構造參數
public ThreadPoolExecutor(int corePoolSize, // 核心線程數int maximumPoolSize, // 最大線程數long keepAliveTime, // 空閑線程存活時間TimeUnit unit, // 時間單位BlockingQueue<Runnable> workQueue, // 任務隊列ThreadFactory threadFactory, // 線程工廠RejectedExecutionHandler handler // 拒絕策略
)
三、常見線程池類型
3.1 FixedThreadPool
固定大小的線程池,核心線程數和最大線程數相等:
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);
3.2 CachedThreadPool
可緩存的線程池,線程數根據需要動態調整:
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
3.3 SingleThreadExecutor
單線程執行器,確保所有任務按順序執行:
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
3.4 ScheduledThreadPool
支持定時任務的線程池:
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
四、線程池的工作流程
- 提交任務:調用
execute()
或submit()
方法提交任務 - 線程池判斷:
- 如果當前線程數小于核心線程數,創建新線程執行任務
- 如果當前線程數大于等于核心線程數,將任務放入任務隊列
- 如果任務隊列已滿且線程數小于最大線程數,創建新線程執行任務
- 如果任務隊列已滿且線程數大于等于最大線程數,執行拒絕策略
- 任務執行完畢:線程返回線程池,等待下一個任務
五、線程池的使用示例
5.1 提交Runnable任務
ExecutorService executor = Executors.newFixedThreadPool(5);for (int i = 0; i < 10; i++) {final int taskId = i;executor.execute(() -> {System.out.println("執行任務: " + taskId);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("任務" + taskId + "執行完畢");});
}executor.shutdown(); // 關閉線程池
5.2 提交Callable任務
ExecutorService executor = Executors.newFixedThreadPool(3);Future<String> future = executor.submit(() -> {Thread.sleep(2000);return "任務執行結果";
});try {String result = future.get(); // 獲取任務結果System.out.println("結果: " + result);
} catch (InterruptedException | ExecutionException e) {e.printStackTrace();
}executor.shutdown();
5.3 定時任務
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);// 延遲3秒后執行任務
scheduler.schedule(() -> {System.out.println("延遲任務執行");
}, 3, TimeUnit.SECONDS);// 延遲1秒后開始執行,每2秒執行一次
scheduler.scheduleAtFixedRate(() -> {System.out.println("定時任務執行");
}, 1, 2, TimeUnit.SECONDS);
六、線程池的拒絕策略
6.1 AbortPolicy(默認)
直接拋出RejectedExecutionException
異常:
new ThreadPoolExecutor.AbortPolicy()
6.2 CallerRunsPolicy
由提交任務的線程自己執行該任務:
new ThreadPoolExecutor.CallerRunsPolicy()
6.3 DiscardPolicy
直接丟棄任務,不做任何處理:
new ThreadPoolExecutor.DiscardPolicy()
6.4 DiscardOldestPolicy
丟棄任務隊列中最老的任務,然后嘗試提交新任務:
new ThreadPoolExecutor.DiscardOldestPolicy()
七、線程池的監控與調優
7.1 監控線程池狀態
ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>()
);// 獲取線程池狀態
int activeCount = executor.getActiveCount(); // 活躍線程數
long completedTaskCount = executor.getCompletedTaskCount(); // 已完成任務數
int queueSize = executor.getQueue().size(); // 隊列中的任務數
7.2 合理配置線程池大小
- CPU密集型任務:線程數 = CPU核心數 + 1
- IO密集型任務:線程數 = CPU核心數 * (1 + 平均等待時間/平均處理時間)
八、線程池的最佳實踐
8.1 避免使用Executors工廠方法
Executors提供的工廠方法可能會創建出有資源耗盡風險的線程池,建議直接使用ThreadPoolExecutor
構造函數:
ExecutorService executor = new ThreadPoolExecutor(5, 10, 60, TimeUnit.SECONDS,new LinkedBlockingQueue<>(100),Executors.defaultThreadFactory(),new ThreadPoolExecutor.CallerRunsPolicy()
);
8.2 正確關閉線程池
executor.shutdown(); // 平緩關閉,等待已提交任務執行完畢
// executor.shutdownNow(); // 立即關閉,嘗試終止正在執行的任務try {if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {executor.shutdownNow();}
} catch (InterruptedException e) {executor.shutdownNow();
}
8.3 使用自定義線程工廠
通過自定義線程工廠可以為線程設置有意義的名稱,便于調試:
ThreadFactory namedThreadFactory = new ThreadFactory() {private final AtomicInteger threadNum = new AtomicInteger(1);@Overridepublic Thread newThread(Runnable r) {return new Thread(r, "my-thread-" + threadNum.getAndIncrement());}
};
若這篇內容幫到你,動動手指支持下!關注不迷路,干貨持續輸出!
ヾ(′? ˋ)ノヾ(′? ˋ)ノヾ(′? ˋ)ノヾ(′? ˋ)ノヾ(′? ˋ)ノ