异步任务
Configuration配置:
需要@EnableAsync
注解开启异步功能。
spring异步任务是通过ThreadPoolTaskExecutor
实现的,实质是线程池,与线程池的配置一样,设置核心线程数量、最大线程数量、线程存活时间、等待队列的容量、任务拒绝策略;
spring执行异步任务就是在相应的线程池中使用线程来执行该异步方法。
@Configuration
@EnableAsync
public class TaskConfigure {
@Bean(name = "taskA")
public TaskExecutor taskA() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程数量
executor.setCorePoolSize(8);
// 最大线程数量
executor.setMaxPoolSize(20);
// 线程存活时间
executor.setKeepAliveSeconds(20);
// 等待队列的容量
executor.setQueueCapacity(200);
// 超过最大线程数量+队列容量后任务的拒绝策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return executor;
}
@Bean(name = "taskB")
public TaskExecutor taskB() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(8);
executor.setMaxPoolSize(20);
executor.setKeepAliveSeconds(20);
executor.setQueueCapacity(200);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return executor;
}
}
异步方法
在方法上使用@Async
注解即成为异步方法,注解的value可填写ThreadPoolTaskExecutor
线程池的bean名称指定使用该线程池,可以在配置中配置多个线程池,不同的任务可以使用不同的线程池
@Component
public class AfterRegisterTask {
private static Logger logger = LoggerFactory.getLogger(AfterRegisterTask.class);
@Async("taskA")
public void sentEmail() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
logger.info("senting email...");
}
@Async("taskB")
public void sentTextMessage() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
logger.info("senting text message...");
}
}
测试代码,模拟注册之后发送邮件和短信
@SpringBootTest
class AfterRegisterTaskTest {
private static Logger logger = LoggerFactory.getLogger(AfterRegisterTask.class);
@Autowired
private AfterRegisterTask task;
@Test
void resister() throws InterruptedException {
logger.info("用户注册");
logger.info("异步方法执行中...");
task.sentEmail();
task.sentTextMessage();
logger.info("立即返回,不用等待异步任务的完成");
// 留出时间给异步方法的线程,不然测试的main线程结束后,异步方法的日志不会打印
Thread.sleep(1500);
}
}
测试结果,方括号中显示的即使线程池名称+线程id,main线程执行了注册,在异步方法执行完成之前就返回了,不会阻塞,开启了异步的方法显示各自使用了配置的线程池里的线程
[ main] com.example.demo.AfterRegisterTask : 用户注册
[ main] com.example.demo.AfterRegisterTask : 异步方法执行中...
[ main] com.example.demo.AfterRegisterTask : 立即返回,不用等待异步任务的完成
[ taskA-1] com.example.demo.AfterRegisterTask : senting email...
[ taskB-1] com.example.demo.AfterRegisterTask : senting text message...
ThreadPoolTaskExecutor
ThreadPoolTaskExecutor
跟jdk里的ThreadPoolExecutor
乍看上去很想,实质上ThreadPoolTaskExecutor
就是封装了一个ThreadPoolExecutor
实例来实现线程池的,ThreadPoolTaskExecutor
的set方法实质都是设置封装的那个线程池对象。
ThreadPoolTaskExecutor
源码:
其中的封装的线程池
@Nullable
private ThreadPoolExecutor threadPoolExecutor;
set方法设置线程池的属性
public void setCorePoolSize(int corePoolSize) {
synchronized (this.poolSizeMonitor) {
this.corePoolSize = corePoolSize;
if (this.threadPoolExecutor != null) {
this.threadPoolExecutor.setCorePoolSize(corePoolSize);
}
}
}
网友评论