# Java 线程池的工作原理
# 1. 线程池概述
线程池是一种管理线程的机制,通过复用一组预先创建的线程来处理大量的并发任务,减少线程的频繁创建和销毁,提升系统性能。Java提供了java.util.concurrent
包中的ExecutorService
接口来管理线程池。
# 2. 线程池的核心组件
Java线程池主要由以下几部分组成:
# 2.1 核心线程数 (corePoolSize
)
- 线程池在空闲时保留的最小线程数量。这些核心线程会一直保留,除非设置了
allowCoreThreadTimeOut
为true
。
# 2.2 最大线程数 (maximumPoolSize
)
- 线程池能够容纳的最大线程数量。超过核心线程数后,线程池可以根据任务需求动态增加线程,直到达到最大线程数。
# 2.3 阻塞队列 (BlockingQueue
)
- 用于存放等待执行的任务。线程池中的空闲线程会从队列中获取任务执行。如果队列满了,且当前线程数量小于
maximumPoolSize
,线程池会创建新的线程。
# 2.4 线程工厂 (ThreadFactory
)
- 线程池使用的线程工厂,用于创建线程。可以通过自定义
ThreadFactory
来为线程命名或设置优先级。
# 2.5 拒绝策略 (RejectedExecutionHandler
)
- 当线程池任务队列已满,且线程数量已经达到
maximumPoolSize
时,线程池会根据拒绝策略处理新提交的任务。常见的拒绝策略有:AbortPolicy
: 抛出RejectedExecutionException
异常。CallerRunsPolicy
: 由提交任务的线程自己执行任务。DiscardPolicy
: 丢弃无法执行的任务。DiscardOldestPolicy
: 丢弃队列中等待最久的任务,执行新任务。
# 2.6 空闲线程存活时间 (keepAliveTime
)
- 当线程池中的线程数量超过
corePoolSize
,如果这些额外的线程在keepAliveTime
时间内处于空闲状态,那么它们将会被终止。
# 3. 线程池的工作流程
任务提交:当有新任务提交时,线程池会进行以下处理:
- 如果当前线程数量少于
corePoolSize
,创建新线程执行任务。 - 如果线程数量达到
corePoolSize
,任务会被放入BlockingQueue
中排队等待执行。 - 如果队列已满,且当前线程数量小于
maximumPoolSize
,线程池会创建新线程执行任务。 - 如果队列满了且线程数量达到
maximumPoolSize
,执行拒绝策略。
- 如果当前线程数量少于
任务执行:线程从任务队列中获取任务,并通过工作线程执行。每个工作线程在执行任务后,会继续从队列中获取下一个任务,直到队列为空或线程被终止。
线程销毁:超过
corePoolSize
的线程在空闲时间超过keepAliveTime
时会被终止,以节省资源。
# 4. 常用的线程池实现
Java提供了多种线程池实现方式,可以通过Executors
工厂类创建。
# 4.1 newFixedThreadPool(int nThreads)
- 创建一个固定大小的线程池,核心线程数和最大线程数都等于
nThreads
,适合执行固定数量的并发任务。
# 4.2 newCachedThreadPool()
- 创建一个根据需求动态调整线程数量的线程池,核心线程数为0,最大线程数为
Integer.MAX_VALUE
,适合执行大量短期任务。
# 4.3 newSingleThreadExecutor()
- 创建一个单线程的线程池,确保所有任务按顺序执行,适合需要串行执行任务的场景。
# 4.4 newScheduledThreadPool(int corePoolSize)
- 创建一个支持定时或周期性执行任务的线程池。
# 5. 线程池工作示例
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExample {
public static void main(String[] args) {
// 创建一个固定大小为5的线程池
ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
executor.submit(() -> {
System.out.println(Thread.currentThread().getName() + " is executing a task.");
});
}
// 关闭线程池
executor.shutdown();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 6. 线程池的优点
- 性能提升:通过线程复用减少线程创建和销毁的开销,适合高并发场景。
- 资源管理:可以根据系统资源动态调整线程数量,避免线程数过多导致系统负载过高。
- 任务调度:通过任务队列和线程池管理,可以有效调度并发任务的执行。
# 7. 注意事项
- 避免线程泄漏:使用线程池时,必须在任务完成后关闭线程池(调用
shutdown()
方法),以避免线程泄漏。 - 合理设置线程数:根据任务的I/O和CPU占用情况合理设置
corePoolSize
和maximumPoolSize
,避免线程过多导致资源竞争。 - 队列类型选择:根据任务特点选择合适的
BlockingQueue
类型(如有界队列、无界队列)控制任务的排队机制。