Java 线程池(Thread Pool)

一、什么是线程池

线程池 是一种线程管理机制,用于提前创建并复用固定数量的线程,以避免频繁地创建/销毁线程带来的资源开销。

主要优势包括:

  • 降低资源消耗(复用线程)
  • 提高响应速度(任务提交后可立即执行)
  • 方便管理线程(线程数可控,支持超时、拒绝策略等)

二、线程池的核心类:ExecutorThreadPoolExecutor

Java 中的线程池定义在 java.util.concurrent 包下,主要接口和类包括:

接口/类名 说明
Executor 线程池顶层接口,定义任务执行方法
ExecutorService 扩展接口,支持任务返回值、关闭池
ThreadPoolExecutor 线程池的核心实现类
Executors 工厂类,用于创建常见线程池
Future 代表异步任务结果

三、使用线程池的三种方式

1. 使用 Executors 工厂类(不推荐用于生产)

1
2
3
4
5
6
7
java复制编辑ExecutorService pool = Executors.newFixedThreadPool(5);

pool.execute(() -> {
System.out.println(Thread.currentThread().getName() + " 执行任务");
});

pool.shutdown();

Executors 提供的几种线程池:

方法 描述
newFixedThreadPool(n) 固定大小线程池
newCachedThreadPool() 可自动扩容线程池(适合短任务)
newSingleThreadExecutor() 单线程池
newScheduledThreadPool(n) 定时/周期性任务线程池

说明:Executors 默认使用 无界队列(如 LinkedBlockingQueue),在任务过多时容易导致内存溢出。推荐手动使用 ThreadPoolExecutor


2. 手动创建 ThreadPoolExecutor(推荐)

1
2
3
4
5
6
7
8
9
java复制编辑ExecutorService pool = new ThreadPoolExecutor(
2, // corePoolSize 核心线程数
5, // maximumPoolSize 最大线程数
60L, // keepAliveTime 空闲线程最大存活时间
TimeUnit.SECONDS, // 时间单位
new ArrayBlockingQueue<>(10), // 等待队列(有界)
Executors.defaultThreadFactory(), // 线程工厂
new ThreadPoolExecutor.AbortPolicy() // 拒绝策略
);

四、线程池任务执行流程

  1. 任务提交给线程池
  2. 如果线程数 < corePoolSize,创建新线程执行任务
  3. 如果线程数 ≥ corePoolSize,任务放入队列等待
  4. 如果队列已满且线程数 < maximumPoolSize,创建新线程执行任务
  5. 如果队列已满且线程数达到最大,触发拒绝策略

五、拒绝策略(RejectedExecutionHandler)

当线程池和队列都满了时,线程池会调用 拒绝策略

策略类 描述
AbortPolicy(默认) 抛出 RejectedExecutionException
CallerRunsPolicy 由提交任务的线程(主线程)执行该任务
DiscardPolicy 直接丢弃任务
DiscardOldestPolicy 丢弃队列中最早的任务,尝试执行当前任务

六、线程池常用方法

1
2
3
4
5
6
7
java复制编辑Future<String> future = pool.submit(() -> {
return "任务执行结果";
});

System.out.println(future.get()); // 获取返回值(阻塞)
java复制编辑pool.shutdown(); // 平滑关闭线程池
pool.shutdownNow(); // 立即关闭线程池(中断正在执行的线程)

七、线程池参数调优建议

参数 调优建议
corePoolSize 根据 CPU 核数和任务类型(I/O密集 or 计算密集)
maximumPoolSize 通常是 core 数的 1.5 ~ 2 倍
队列类型 推荐使用有界队列(如 ArrayBlockingQueue)
拒绝策略 根据业务场景选择(如降级、记录日志)
keepAliveTime 非核心线程空闲存活时间

八、实际开发中的应用场景

  • Web 服务器处理请求(如 Tomcat 使用线程池处理 Servlet 请求)
  • 数据库连接池底层使用线程池管理连接
  • 消息处理系统(异步处理消息队列中的任务)
  • 定时任务调度(使用 ScheduledExecutorService

九、示例:批量执行任务并收集返回值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
java复制编辑ExecutorService pool = Executors.newFixedThreadPool(3);

List<Future<Integer>> futures = new ArrayList<>();
for (int i = 0; i < 5; i++) {
int num = i;
futures.add(pool.submit(() -> {
Thread.sleep(1000);
return num * num;
}));
}

for (Future<Integer> f : futures) {
System.out.println("结果:" + f.get());
}

pool.shutdown();

十、补充:线程池监控与可视化

可以通过以下方式监控线程池运行状态:

1
2
3
4
5
6
java复制编辑ThreadPoolExecutor pool = (ThreadPoolExecutor) Executors.newFixedThreadPool(3);

System.out.println(pool.getPoolSize()); // 当前线程池大小
System.out.println(pool.getActiveCount()); // 活跃线程数
System.out.println(pool.getQueue().size()); // 队列长度
System.out.println(pool.getCompletedTaskCount());// 完成任务数