"作為一名Java開發者,是否曾經遇到過多線程并發的問題?線程數量過多時,會導緻資源浪費,應用性能下降,甚至發生線程死鎖的情況。那麼,有沒有一種方法可以有效地管理線程,避免這些問題呢?答案是肯定的,那就是線程池。在本文中,我們将通過Java的角度,探讨線程池的奧妙,深入了解線程池的優勢,學習如何使用線程池實作多線程并發。"
線程池是如何建立的?
JAVA中建立線程池主要有兩類方法,一類是通過Executors工廠類提供的方法,該類提供了4種不同的線程池可供使用。另一類是通過ThreadPoolExecutor類進行自定義建立。
Executors工廠類
// 五種線程池:
// ExecutorService threadPool = null;
// threadPool = Executors.newCachedThreadPool();//有緩沖的線程池,線程數 JVM 控制
// threadPool = Executors.newFixedThreadPool(3);//固定大小的線程池
// threadPool = Executors.newScheduledThreadPool(2); // 具有延時,定時功能
// threadPool = Executors.newSingleThreadExecutor();//單線程的線程池,隻有一個線程在工作
// threadPool = new ThreadPoolExecutor();//預設線程池,可控制參數比較多
private static void createCachedThreadPool() {
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
final int index = i;
executorService.execute(() -> {
// 擷取線程名稱,預設格式:pool-1-thread-1
System.out.println(DateUtil.now() + " " + Thread.currentThread().getName() + " " + index);
// 等待2秒
sleep(2000);
});
}
}
ThreadPoolExecutor類
ThreadPoolExecutor提供構造方法,需要自己設定具體的參數,更加靈活
public ThreadPoolExecutor(int corePoolSize, // 核心線程數
int maximumPoolSize, // 最大工作線程
long keepAliveTime, // 存活時間,線程沒有任務執行時最多保持多久時間會終止。
TimeUnit unit, // 時間機關
BlockingQueue<Runnable> workQueue, // 工作隊列
ThreadFactory threadFactory, // 線程工廠,主要用來建立線程,默及正常優先級、非守護線程。
RejectedExecutionHandler handler // 拒絕政策,當建立新線程使線程數大于最大線程的情況下,會執行
) {
// 省略...
}
線程池的主要參數
- corePoolSize 核心線程數 核心線程數,線程池中始終存活的線程數。
- BlockingQueue 工作隊列 workQueue = new ArrayBlockingQueue<>(5);//基于數組的先進先出隊列,有界 workQueue = new LinkedBlockingQueue<>();//基于連結清單的先進先出隊列,無界 workQueue = new SynchronousQueue<>();//無緩沖的等待隊列,無界
- threadFactory 線程工廠 用于設定建立線程的工廠,可以通過線程工廠給每個建立出來的。線程設定更有意義的名字。使用開源架構 guava 提供的 ThreadFactoryBuilder 可以快速給線程池裡的線程設定有意義的名字,代碼如下:
new ThreadFactoryBuilder().setNameFormat("XX-task-%d").build();
- handler 拒絕政策,拒絕處理任務時的政策,4種可選,預設為AbortPolicy。
參數 描述 AbortPolicy 拒絕并抛出異常 CallerRunsPolicy 隻用調用者所線上程來運作任務 DiscardOldestPolicy 抛棄隊列頭部(最舊)的一個任務,并執行目前任務。 DiscardPolicy 抛棄目前任務。
RejectedExecutionHandler rejected = null;
rejected = new ThreadPoolExecutor.AbortPolicy();//預設,隊列滿了丢任務抛出異常
rejected = new ThreadPoolExecutor.DiscardPolicy();//隊列滿了丢任務不異常
rejected = new ThreadPoolExecutor.DiscardOldestPolicy();//将最早進入隊列的任務删,之後再嘗試加入隊列
rejected = new ThreadPoolExecutor.CallerRunsPolicy();//如果添加到線程池失敗,那麼主線程會自己去執行
線程池的執行過程?
- 主線程送出任務到線程池,如果目前線程數小于核心線程數,建立新的線程用于執行任務,如果不是,下一步。
- 此時核心線程已滿,再判斷工作隊列存放的線程數是否滿了,如果沒有滿,則放入工作隊列,如果不是,下一步。
- 此時工作隊列滿了,再看目前線程數是否等于最大線程數,如果是的話,執行拒絕政策,如果不是,建立新的線程,執行任務。
配置線程池最大線程數
- cpu密集型 maximumPoolSize = n*cpu + 1
- io密集型 maximumPoolSize = 2 * n * cpu
線程池的關閉
可以通過調用線程池的 shutdown 或 shutdownNow 方法來關閉線程池。 相同點:周遊所有的工作線程,然後interrupt掉線程 不同點:shutdown 調用後,不再接受新的任務,但是會等待正在運作的線程,停止沒有執行任務的線程。 shutdownNow 調用後會嘗試停止正在運作或暫停任務的線程。
原創不易,麻煩點個贊再走呗!