线程池配置类
package com.memento.common.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* @author Memento
* 1. 创建线程池后, 线程池中的线程数为 0;
* 2. 任务过来之后开始创建线程执行;
* 3. 当线程数达到 corePoolSize 后, 会把任务放到缓存队列 queueCapacity 中;
* 4. 当缓存队列满了之后, 继续创建线程执行任务;
* 5. 当线程数达到 maxPoolSize 后, 开始使用拒绝策略拒绝任务;
*/
@Configuration
@EnableAsync
public class ThreadPoolTaskConfig {
/** 核心线程数(默认线程数), 默认值=1 **/
private static final int CORE_POOL_SIZE = 20;
/** 最大线程数, 默认值=2147483647 **/
private static final int MAX_POOL_SIZE = 100;
/** 缓冲队列大小, 默认值=2147483647 **/
private static final int QUEUE_CAPACITY = 200;
/** 允许线程空闲时间(单位: s), 默认值=60 **/
private static final int KEEP_ALIVE_TIME = 10;
/** 线程池名前缀 **/
private static final String THREAD_NAME_PREFIX = "Async-Service-";
@Bean("taskExecutor")
public ThreadPoolTaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(CORE_POOL_SIZE);
executor.setMaxPoolSize(MAX_POOL_SIZE);
executor.setQueueCapacity(QUEUE_CAPACITY);
executor.setKeepAliveSeconds(KEEP_ALIVE_TIME);
executor.setThreadNamePrefix(THREAD_NAME_PREFIX);
// 设置拒绝策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 初始化
executor.initialize();
return executor;
}
}
最大任务数
=maxPoolSize
+queueCapacity
拒绝策略:
CallerRunsPolicy
, 当任务数超过最大任务数
后, 该策略表示后续任务直接执行;AbortPolicy
, 当任务数超过最大任务数
后, 该策略表示直接拒绝任务, 但是会抛出RejectedExecutionException
给主线程;DiscardPolicy
, 当任务数超过最大任务数
后, 该策略表示直接忽略任务, 对主线程无任何影响;DiscardOldestPolicy
, 当任务数超过最大任务数
后, 该策略表示忽略最旧的任务, 并把后续的任务插入队列, 对主线程无任何影响;
Async 注解使用
@Async("taskExecutor")
public void sendMessage1() throws InterruptedException {
logger.info("发送短信方法---- 1 执行开始");
// 模拟耗时
Thread.sleep(5000);
logger.info("发送短信方法---- 1 执行结束");
}
@Async("taskExecutor")
指定使用自定义线程池 @Bean("taskExecutor")
;
注意事项
以下方式会使 @Async
失效:
- 异步方法用
static
修饰; (经验证, 现在的@Async
标注的方法, 无法加static
作为静态方法)
- 异步类没有使用
@Component
注解, 或其他注解, 导致spring
无法扫描到异步类; - 异步方法不能与被调用的异步方法在同一个类中; (核实正确)
- 类中需要使用
@Autowired
或@Resource
等注解自动注入, 不能手动 new 对象; (这里应该是指线程池配置类) 如果使用SpringBoot框架必须在启动类中增加@EnableAsync注解(经验证, 可以不在启动类中增加@EnableAsync
注解)