点击下载《SpringBoot线程池详解含完整示例(值得珍藏)》
1. 摘要
Spring Boot中内置了多种线程池,为应用程序提供快速响应和高吞吐量的运行环境。线程池在Spring Boot中起着至关重要的作用,它能够有效地管理和复用线程,降低系统的开销。本文将详细介绍线程池的基本参数、每一种线程池类型的特性,以及常见的拒绝策略。同时,我们将提供完整的源代码和注释,帮助您更好地理解和应用线程池。
2. 线程池在Spring Boot中的重要性
在Spring Boot应用中,线程池是实现并发编程的关键组件。通过合理配置线程池,我们可以控制并发任务的执行,优化系统资源利用率,提高应用的性能和响应速度。
2.1 Spring Boot中的线程池类型
- SingleThreadExecutor:单线程化的Executor,它将所有的任务都在一个单一的线程上顺序执行。这可以保证任务的顺序执行,但性能不如FixedThreadPool。
- FixedThreadPool:固定容量线程池。其特点是最大线程数就是核心线程数,意味着线程池只能创建核心线程,keepAliveTime为0,即线程执行完任务立即回收。任务队列未指定容量,代表使用默认值
Integer.MAX_VALUE
。适用于需要控制并发线程的场景。 - CachedThreadPool:用于在给定的延迟后运行命令或者定期执行的线程池。它比Timer更易用,也更强大。它允许在固定延迟后运行命令,以及定期执行命令。它是非守护线程池。
- ScheduledThreadPool:用于在给定的延迟后运行命令或者定期执行的线程池。它比Timer更易用,也更强大。它允许在固定延迟后运行命令,以及定期执行命令。它是非守护线程池。
2.2 线程池的基本参数
线程池的基本参数主要包括以下几种:
- corePoolSize(必需): 核心线程数。即池中一直保持存活的线程数,即使这些线程处于空闲。但是将allowCoreThreadTimeOut参数设置为true后,核心线程处于空闲一段时间以上,也会被回收。
- maximumPoolSize(必需): 池中允许的最大线程数。当核心线程全部繁忙且任务队列打满之后,线程池会临时追加线程,直到总线程数达到maximumPoolSize这个上限。
- keepAliveTime(必需): 线程空闲超时时间。当非核心线程处于空闲状态的时间超过这个时间后,该线程将被回收。将allowCoreThreadTimeOut参数设置为true后,核心线程也会被回收。
- unit(必需): keepAliveTime参数的时间单位。有:
TimeUnit.DAYS
(天)、TimeUnit.HOURS
(小时)、TimeUnit.MINUTES
(分钟)、TimeUnit.SECONDS
(秒)、TimeUnit.MILLISECONDS
(毫秒)、TimeUnit.MICROSECONDS
(微秒)、TimeUnit.NANOSECONDS
(纳秒) - workQueue(必需): 任务队列,采用阻塞队列实现。当核心线程全部繁忙时,后续由execute方法提交的Runnable将存放在任务队列中,等待被线程处理。
- threadFactory(可选): 线程工厂。指定线程池创建线程的方式。
- handler(可选): 拒绝策略。当线程池中线程数达到maximumPoolSize且workQueue打满时,后续提交的任务将被拒绝,handler可以指定用什么方式拒绝任务。
2.3 线程池的配置
在Spring Boot中,可以通过以下方式配置线程池:
- 属性配置:在
application.properties
或application.yml
中设置相关属性。例如:spring.datasource.hikari.pool-size
用于设置Hikari连接池大小。 - Java配置:使用
@Bean
注解定义线程池。例如:
@Bean(name = "taskExecutor")
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(25);
executor.setThreadNamePrefix("taskExecutor-");
executor.initialize();
return executor;
}
- XML配置:使用
<task:executor>
元素配置线程池。例如:
<task:executor id="taskExecutor" core-pool-size="5" max-pool-size="10" queue-capacity="25" thread-name-prefix="taskExecutor-" />
2.3 拒绝策略
线程池有一个重要的机制:拒绝策略。当线程池工作队列已满且无法再创建新线程池时,就要拒绝后续任务了。拒绝策略需要实现RejectedExecutionHandler
接口,不过Executors框架已经为我们实现了4种拒绝策略:
- AbortPolicy(默认): 丢弃任务并抛出RejectedExecutionException异常。
- CallerRunsPolicy: 直接运行这个任务的run方法,但并非是由线程池的线程处理,而是交由任务的调用线程处理。
- DiscardPolicy: 直接丢弃任务,不抛出任何异常。
- DiscardOldestPolicy: 将当前处于等待队列列头的等待任务强行取出,然后再试图将当前被拒绝的任务提交到线程池执行。
2.4 线程池的状态
- RUNNING: 当创建线程池后,初始时,线程池处于RUNNING状态;
- SHUTDOWN: 如果调用了shutdown()方法,则线程池处于SHUTDOWN状态,此时线程池不能够接受新的任务,它会等待所有任务执行完毕;
- STOP: 如果调用了shutdownNow()方法,则线程池处于STOP状态,此时线程池不能接受新的任务,并且会去尝试终止正在执行的任务;
- TERMINATED: 当线程池处于SHUTDOWN或STOP状态,并且所有工作线程已经销毁,任务缓存队列已经清空或执行结束后,线程池被设置为TERMINATED状态。
2.4 线程池的使用场景
- 数据库连接池:如HikariCP、C3P0等,用于管理数据库连接。
- 任务调度:如使用ScheduledThreadPoolExecutor实现定时任务。
- 异步处理:使用ThreadPoolTaskExecutor处理耗时操作,提高响应速度。
- 分布式系统:在微服务架构中,服务间调用可以使用线程池来管理并发请求。
2.5 注意事项
- 合理选择线程池类型,根据实际需求选择合适的线程池。
- 配置合适的线程池参数,如核心线程数、最大线程数、队列容量等。
- 监控线程池状态,避免资源耗尽或浪费。
- 注意线程安全问题,避免多线程环境下的数据竞争和死锁。
2.6 使用示例
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
public class FixedThreadPoolExample {
public static void main(String[] args) {
// 创建一个固定大小的线程池
ExecutorService executor = Executors.newFixedThreadPool(5);
// 提交任务到线程池
for (int i = 0; i < 10; i++) {
Runnable worker = new WorkerThread("" + i);
executor.execute(worker);
}
// 关闭线程池
executor.shutdown();
}
}
class WorkerThread implements Runnable {
private String command;
public WorkerThread(String s) {
this.command = s;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " Start. Command = " + command);
processCommand();
System.out.println(Thread.currentThread().getName() + " End.");
}
private void processCommand() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
- SingleThreadExecuto与FixedThreadPool相似,只是使用了
Executors.newSingleThreadExecutor()
来创建线程池。 - ScheduledThreadPool与FixedThreadPool相似,只是使用了
Executors.newScheduledThreadPool
来创建线程池。 - CachedThreadPool与FixedThreadPool相似,只是使用了
Executors.newCachedThreadPool
来创建线程池。
3. 总结
Spring Boot中的线程池为开发者提供了强大的并发支持。通过合理配置和使用线程池,我们可以优化系统性能,提高应用的响应速度和吞吐量。深入理解Spring Boot中的线程池,并根据实际需求进行合理的配置和使用,是每个Spring Boot开发者的必备技能。