Java 线程池技术笔记
一、线程池基础
1. 什么是线程池
程序启动时创建固定数量线程存入池中待命,任务到来取出空闲线程执行,任务完成线程不销毁,回归池中等候新任务。
2. 线程池优点
- 降低资源消耗:避免频繁创建/销毁线程
- 提高响应速度:线程已存在,无需等待创建
- 提高可管理性:统一分配、监控、调优
- 防止资源耗尽:限制并发线程数,避免系统崩溃
3. Java 线程池核心组件
- 核心接口:
ExecutorService - 常用实现:
ThreadPoolExecutor// 生产环境推荐使用 - 工具类:
Executors// 提供快捷创建方式,生产慎用
二、ThreadPoolExecutor 核心参数
java
public ThreadPoolExecutor(
int corePoolSize, // 核心线程数,常驻不销毁
int maximumPoolSize, // 最大线程数,包含核心+临时
long keepAliveTime, // 空闲线程存活时间
TimeUnit unit, // 时间单位
BlockingQueue<Runnable> workQueue, // 任务阻塞队列
ThreadFactory threadFactory, // 线程工厂,自定义线程名/属性
RejectedExecutionHandler handler // 拒绝策略
)
执行逻辑(重点)
- 线程数 < corePoolSize → 新建核心线程执行
- 线程数 ≥ corePoolSize → 任务入队列
- 队列满 且 线程数 < maximumPoolSize → 新建临时线程
- 队列满 且 线程数 = maximumPoolSize → 触发拒绝策略
三、标准使用代码示例
java
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
public class ThreadPoolExample {
public static void main(String[] args) {
// 1. 自定义线程池参数
int corePoolSize = 2;
int maxPoolSize = 4;
long keepAliveTime = 10;
// 任务队列容量2
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(2);
// 自定义线程工厂 // 方便日志定位问题
ThreadFactory threadFactory = new ThreadFactory() {
private final AtomicInteger threadNumber = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, "my-pool-thread-" + threadNumber.getAndIncrement());
t.setDaemon(false); // 非守护线程,保证任务执行完
return t;
}
};
// 拒绝策略
RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
// 创建线程池
ExecutorService executor = new ThreadPoolExecutor(
corePoolSize,
maxPoolSize,
keepAliveTime,
TimeUnit.SECONDS,
workQueue,
threadFactory,
handler
);
// 2. 提交10个任务
for (int i = 1; i <= 10; i++) {
final int taskId = i;
executor.submit(() -> {
String threadName = Thread.currentThread().getName();
System.out.printf("[%s] 开始执行任务 %d%n", threadName, taskId);
try {
TimeUnit.SECONDS.sleep(1); // 模拟业务执行
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 恢复中断位
}
System.out.printf("[%s] 完成任务 %d%n", threadName, taskId);
});
}
// 3. 关闭线程池 // 必须关闭,否则进程不退出
executor.shutdown();
try {
// 等待最多30秒
if (!executor.awaitTermination(30, TimeUnit.SECONDS)) {
executor.shutdownNow(); // 超时强制关闭
}
} catch (InterruptedException e) {
executor.shutdownNow();
}
System.out.println("所有任务执行完毕,线程池已关闭");
}
}
四、Executors 快捷线程池
java
// 固定线程数 // 队列无界,生产可能OOM
ExecutorService fixedPool = Executors.newFixedThreadPool(5);
// 单线程线程池 // 保证顺序执行
ExecutorService singlePool = Executors.newSingleThreadExecutor();
// 按需创建线程 // 线程数无界,高并发风险
ExecutorService cachedPool = Executors.newCachedThreadPool();
// 定时/周期任务
ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(3);
定时任务示例
java
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
// 1秒后开始,每3秒执行一次
scheduler.scheduleAtFixedRate(() -> {
System.out.println("heartbeat");
}, 1, 3, TimeUnit.SECONDS);
scheduler.shutdown();
五、拒绝策略
AbortPolicy():抛出异常,默认策略CallerRunsPolicy():调用者线程执行 // 温和限流DiscardPolicy():直接丢弃,不抛异常DiscardOldestPolicy():丢弃队列最老任务,重试提交
六、线程池监控(常用方法)
java
ThreadPoolExecutor pool = (ThreadPoolExecutor) executor;
pool.getPoolSize(); // 当前线程总数
pool.getActiveCount(); // 活跃线程数
pool.getQueue().size(); // 队列等待任务数
pool.getCompletedTaskCount();// 已完成任务数
七、生产注意事项
-
必须关闭线程池
非守护线程会导致进程无法退出,用
shutdown()/shutdownNow()。 -
任务必须捕获异常
任务未捕获异常会导致线程被销毁,线程池重建线程,推荐任务内
try-catch。 -
禁止滥用 Executors
生产直接用
ThreadPoolExecutor,避免队列/线程数无界导致OOM。 -
合理设置参数
CPU密集型:核心线程数 ≈ CPU核心数
IO密集型:核心线程数 ≈ 2*CPU核心数
八、配套实战案例(敏感词检测)
java
import java.util.Random;
import java.util.concurrent.*;
// 网络服务类,持续生成任务提交线程池
class NetworkService implements Runnable {
final ThreadPoolExecutor pool;
public NetworkService(int poolSize) {
// 自定义线程池,生产标准写法
this.pool = new ThreadPoolExecutor(
poolSize,
30,
3000,
TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<>(100)
);
}
@Override
public void run() {
long start = System.currentTimeMillis();
Random random = new Random();
while (true) {
// 生成随机字符串
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 20; i++) {
sb.append((char) (random.nextInt(126 - 32) + 32));
}
// 提交任务
pool.execute(new Handler(sb.toString()));
// 运行100秒后关闭线程池
if (System.currentTimeMillis() - start > 100000) {
pool.shutdown();
break;
}
}
}
}
// 任务处理器:检测是否包含敏感词a
class Handler implements Runnable {
private final String str;
public Handler(String str) {
this.str = str;
}
@Override
public void run() {
try {
Thread.sleep(1000); // 模拟处理耗时
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
if (str.contains("a")) {
System.out.println(str + ": 包含敏感词");
} else {
System.out.println(str + ": 不包含敏感词");
}
}
}
// 主类
class Main {
public static void main(String[] args) {
NetworkService service = new NetworkService(10);
new Thread(service).start();
// 监控线程池状态
new Thread(() -> {
while (true) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
break;
}
ThreadPoolExecutor pool = service.pool;
System.out.println("ActiveCount: " + pool.getActiveCount());
System.out.println("PoolSize: " + pool.getPoolSize());
System.out.println("TaskCount: " + pool.getTaskCount());
}
}).start();
}
}