優點
ThreadPoolExecutor 提供了強大的靈活性和自定義參數的能力,可以根據實際需求來靈活配置線程池的行為。
位置
????????java.util.concurrent 包下
構造函數
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory)public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler)\public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
核心參數
corePoolSize:線程池的基本大小,即使沒有任務執行時也保持存活的線程數。
maximumPoolSize:線程池所能容納的最大線程數(包括核心線程)。
keepAliveTime:非核心線程空閑等待新任務的最長時間,在這個時間內如果沒有新任務提交,那么非核心線程將會被終止。
unit:與keepAliveTime搭配使用的單位,如TimeUnit.SECONDS或TimeUnit.MILLISECONDS等。
workQueue:任務隊列,用于保存待處理的任務,可以是無界隊列(例如LinkedBlockingQueue)或有界隊列(例如ArrayBlockingQueue)。
threadFactory:創建新線程的工廠,默認使用Executors.defaultThreadFactory(),也可以自定義來設置線程名稱、優先級等屬性。
handler:拒絕策略,當線程池和工作隊列都已滿,無法接收新的任務時,會調用此策略進行處理。AbortPolicy(直接拋出異常);CallerRunsPolicy(由調用者線程自己執行任務);DiscardPolicy(直接丟棄新任務);DiscardOldestPolicy(丟棄隊列中最舊的任務并嘗試提交當前任務)。
線程池工作流程
當一個任務提交到ThreadPoolExecutor時:
如果當前運行的線程數量小于corePoolSize,則創建一個新的線程來執行任務。
若當前線程數等于corePoolSize但小于maximumPoolSize,且工作隊列已滿,則創建新的線程來執行任務。
如果線程數已經達到maximumPoolSize并且工作隊列也滿了,則根據RejectedExecutionHandler策略處理該任務。
線程池狀態
線程池具有五種狀態:RUNNING、SHUTDOWN、STOP、TIDYING 和 TERMINATED。
狀態轉換通常發生在調用諸如shutdown(), shutdownNow(), 或者所有任務完成后
重要方法
shutdown():線程池不再接受新的任務,但會繼續處理已經提交的任務。
shutdownNow():嘗試停止所有正在執行的任務,并返回尚未開始執行的任務列表。
execute(Runnable command):提交一個Runnable任務給線程池執行。
submit(Callable<T> task):提交一個Callable任務,能夠返回結果。
awaitTermination(long timeout, TimeUnit unit):阻塞當前線程,直到線程池關閉或者超時發生。
isTerminated():檢查線程
示例
? ? ? ? 示例1:
package org.springblade.test;import lombok.extern.slf4j.Slf4j;import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;@Slf4j
public class Test {@org.junit.jupiter.api.Testpublic void ThreadPoolExecutorExample() {// 自定義線程工廠ThreadFactory namedThreadFactory = new NamedThreadFactory();// 創建有界任務隊列BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(10);// 定義拒絕策略RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();// 創建線程池ThreadPoolExecutor executor = new ThreadPoolExecutor(2, // 核心線程數4, // 最大線程數60L, // 空閑線程存活時間(單位:秒)TimeUnit.SECONDS, // 時間單位workQueue, // 工作隊列namedThreadFactory, // 線程工廠handler // 拒絕策略);// 提交任務到線程池for (int i = 0; i < 20; i++) {final int taskId = i;Runnable worker = new Runnable() {@Overridepublic void run() {System.out.println("Task " + taskId + " is running by " + Thread.currentThread().getName());try {Thread.sleep(500); // 模擬耗時操作} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Task " + taskId + " finished");}};executor.execute(worker);}// 關閉線程池executor.shutdown();while (!executor.isTerminated()) {// 等待所有任務執行完畢}System.out.println("所有任務已完成,線程池已關閉");}
}/*** 定義線程創建邏輯,設置線程名稱前綴等*/
class NamedThreadFactory implements ThreadFactory {private static final AtomicInteger poolNumber = new AtomicInteger(1);private final ThreadGroup group;private final AtomicInteger threadNumber = new AtomicInteger(1);private final String namePrefix;NamedThreadFactory() {SecurityManager s = System.getSecurityManager();group = (s != null) ? s.getThreadGroup() :Thread.currentThread().getThreadGroup();namePrefix = "MyTaskPool-" + poolNumber.getAndIncrement() + "-thread-";}@Overridepublic Thread newThread(Runnable r) {Thread t = new Thread(group, r,namePrefix + threadNumber.getAndIncrement(),0);if (t.isDaemon())t.setDaemon(false);if (t.getPriority() != Thread.NORM_PRIORITY)t.setPriority(Thread.NORM_PRIORITY);return t;}
}
//我們提交了20個任務到線程池。由于工作隊列容量有限(10),當隊列滿后會嘗試增加線程直到達到最大線程數(4)。
//如果在達到最大線程數后仍有新的任務提交,將根據指定的拒絕策略處理這些任務。
// 在本例中,我們選擇了 CallerRunsPolicy,這意味著超出線程池處理能力的任務將會由調用者線程(主線程)直接執行。
//執行結果
//Task 0 is running by MyTaskPool-1-thread-1
// Task 14 is running by main
// Task 1 is running by MyTaskPool-1-thread-2
// Task 13 is running by MyTaskPool-1-thread-4
// Task 12 is running by MyTaskPool-1-thread-3
// Task 12 finished
// Task 1 finished
// Task 0 finished
// Task 13 finished
// Task 14 finished
// Task 4 is running by MyTaskPool-1-thread-3
// Task 19 is running by main
// Task 5 is running by MyTaskPool-1-thread-4
// Task 3 is running by MyTaskPool-1-thread-1
// Task 2 is running by MyTaskPool-1-thread-2
// Task 5 finished
// Task 4 finished
// Task 19 finished
// Task 3 finished
// Task 8 is running by MyTaskPool-1-thread-1
// Task 2 finished
// Task 9 is running by MyTaskPool-1-thread-2
// Task 7 is running by MyTaskPool-1-thread-3
// Task 6 is running by MyTaskPool-1-thread-4
// Task 8 finished
// Task 10 is running by MyTaskPool-1-thread-1
// Task 6 finished
// Task 9 finished
// Task 7 finished
// Task 15 is running by MyTaskPool-1-thread-2
// Task 11 is running by MyTaskPool-1-thread-4
// Task 16 is running by MyTaskPool-1-thread-3
// Task 10 finished
// Task 17 is running by MyTaskPool-1-thread-1
// Task 11 finished
// Task 15 finished
// Task 16 finished
// Task 18 is running by MyTaskPool-1-thread-4
// Task 17 finished
// Task 18 finished
// 所有任務已完成,線程池已關閉
????????示例2:
package org.springblade.test;import lombok.extern.slf4j.Slf4j;import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;@Slf4j
public class Test {@org.junit.jupiter.api.Testpublic void ThreadPoolExecutorExample() {// 定義核心線程數、最大線程數、空閑線程存活時間以及時間單位int corePoolSize = 5;int maximumPoolSize = 10;long keepAliveTime = 60; // 60秒TimeUnit unit = TimeUnit.SECONDS;// 創建一個有界的LinkedBlockingQueue作為任務隊列,容量為20BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(20);// 創建線程池ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,unit,workQueue);// 提交任務到線程池for (int i = 0; i < 30; i++) {final int taskId = i;Runnable worker = () -> {System.out.println("Task " + taskId + " is running by " + Thread.currentThread().getName());try {Thread.sleep(1000); // 模擬耗時操作} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Task " + taskId + " finished");};executor.execute(worker);}// 關閉線程池(這里沒有立即關閉,而是等待所有任務執行完畢)executor.shutdown();while (!executor.isTerminated()) {// 等待所有任務執行完畢}System.out.println("所有任務已完成,線程池已關閉");}
}//執行結果
// Task 0 is running by pool-1-thread-1
// Task 1 is running by pool-1-thread-2
// Task 3 is running by pool-1-thread-4
// Task 2 is running by pool-1-thread-3
// Task 4 is running by pool-1-thread-5
// Task 25 is running by pool-1-thread-6
// Task 26 is running by pool-1-thread-7
// Task 27 is running by pool-1-thread-8
// Task 29 is running by pool-1-thread-10
// Task 28 is running by pool-1-thread-9
// Task 2 finished
// Task 0 finished
// Task 3 finished
// Task 5 is running by pool-1-thread-1
// Task 6 is running by pool-1-thread-4
// Task 7 is running by pool-1-thread-3
// Task 1 finished
// Task 8 is running by pool-1-thread-2
// Task 4 finished
// Task 9 is running by pool-1-thread-5
// Task 25 finished
// Task 10 is running by pool-1-thread-6
// Task 27 finished
// Task 28 finished
// Task 26 finished
// Task 13 is running by pool-1-thread-7
// Task 29 finished
// Task 14 is running by pool-1-thread-10
// Task 11 is running by pool-1-thread-8
// Task 12 is running by pool-1-thread-9
// Task 7 finished
// Task 15 is running by pool-1-thread-3
// Task 5 finished
// Task 16 is running by pool-1-thread-1
// Task 6 finished
// Task 17 is running by pool-1-thread-4
// Task 8 finished
// Task 18 is running by pool-1-thread-2
// Task 9 finished
// Task 19 is running by pool-1-thread-5
// Task 10 finished
// Task 20 is running by pool-1-thread-6
// Task 12 finished
// Task 21 is running by pool-1-thread-9
// Task 14 finished
// Task 11 finished
// Task 22 is running by pool-1-thread-8
// Task 23 is running by pool-1-thread-10
// Task 13 finished
// Task 24 is running by pool-1-thread-7
// Task 15 finished
// Task 17 finished
// Task 16 finished
// Task 18 finished
// Task 19 finished
// Task 20 finished
// Task 23 finished
// Task 22 finished
// Task 24 finished
// Task 21 finished