本文主要介紹了Java自定義參數創建線程池的示例,其中也使用了java的並發工具類CountDownLatch和CyclicBarrier(順便練習一下他們的用法),記錄第一次發博客
使用線程池的好處
- 降低資源消耗。通過重復利用已創建的線程降低線程創建和銷毀造成的消耗。
- 提高響應速度。當任務到達時,任務可以不需要的等到線程創建就能立即執行。
- 提高線程的可管理性。線程是稀缺資源,如果無限制的創建,不僅會消耗系統資源,還會降低系統的穩定性,使用線程池可以進行統一的分配,調優和監控。
通過Executors工具類創建的線程池的弊端
FixedThreadPool
和SingleThreadExecutor
使用無界隊列LinkedBlockingQueue
(隊列的容量為 Intger.MAX_VALUE)作為線程池的工作隊列,可能堆積大量的請求,從而導致 OOM。- ScheduledThreadPoolExecutor使用無界隊列DelayQueue(隊列的容量為 Intger.MAX_VALUE)作為線程池的工作隊列,可能堆積大量的請求,從而導致 OOM。
CachedThreadPool
允許創建的線程數量為 Integer.MAX_VALUE ,可能會創建大量線程,從而導致 OOM。
自定義參數創建線程池示例
package thread; import java.util.concurrent.*; public class ThreadPoolDemo { //線程池的核心線程數量 private static final int CORE_POOL_SIZE = 5; //線程池的最大線程數 private static final int MAX_POOL_SIZE = 10; //阻塞隊列的容量 private static final int QUEUE_CAPACITY = 100; //當線程數大於核心線程數時,多余的空閑線程存活的最長時間 private static final Long KEEP_ALIVE_TIME = 1L; public static int threadNum = 5; public static void main(String[] args) throws InterruptedException { CountDownLatch countDownLatch = new CountDownLatch(threadNum); CyclicBarrier cyclicBarrier = new CyclicBarrier(threadNum); //使用阿里巴巴推薦的創建線程池的方式 //通過ThreadPoolExecutor構造函數自定義參數創建 ThreadPoolExecutor executor = new ThreadPoolExecutor( CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.SECONDS, new ArrayBlockingQueue<>(QUEUE_CAPACITY), //線程池達到飽和之后的拒絕策略, // 調用執行自己的線程運行任務,也就是直接在調用execute方法的線程中運行被拒絕的任務 new ThreadPoolExecutor.CallerRunsPolicy()); for (int i = 0; i < threadNum; i++) { //簡潔的Lambda表達式 executor.execute(() -> { try { //當前線程阻塞,直到所有線程都准備就緒 cyclicBarrier.await(); System.out.println( "當前線程: "+ Thread.currentThread().getName() + " 開始工作啦"); //模擬業務代碼 Thread.sleep(1000); System.out.println( "當前線程: "+ Thread.currentThread().getName() + " 結束工作啦"); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } countDownLatch.countDown(); }); } //主線程等待工作線程全部結束 countDownLatch.await(); //關閉線程池 executor.shutdown(); System.out.println("全部線程工作完成"); } }