springboot使用@async实现异步线程池
一 介绍
工作中经常涉及异步任务,通常是使用多线程技术,比如线程池ThreadPoolExecutor,但使用Executors容易产生OOM,需要手动使用ThreadPoolExecutor创建线程池;在springboot使用 @async 可以实现异步调用,配置线程池参数,可以简单的实现多线程的线程池效果,从而简化开发,避免OOM;
二 异步调用
2.1无返回异步
我们知道同步执行就是按照代码的顺序执行,而异步执行则是无序,在springboot中使用实现异步调用函数非常简单,首先在启动类上加上@EnableAsync
注解;
/**
* @Author lsc
* <p> </p>
*/
@SpringBootApplication
@EnableAsync
public class AsyncRunApp {
public static void main(String[] args) {
SpringApplication.run(AsyncRunApp.class, args);
}
}
其次,在函数上标上@sync
注解,表示异步调用
@Async
public void taskOne() throws Exception {
System.out.println("任务一");
}
@Async
public void taskTwo() throws Exception {
System.out.println("任务二");
}
测试代码
@Autowired
Task task;
@Test
public void test() throws Exception {
task.taskOne();
task.taskTwo();
}
如果按照同步执行逻辑会先执行任务一,然后再执行任务二,如果是异步执行,则无序,可能任务一先执行,也可能任务二先执行;
2.2 有返回值回调
有时候要知道任务是否执行完成,再继续做其它的业务逻辑,就需要使用到Future接口,其含义是在执行异步任务后会给一个回调函数,我们只要设置回调信息,就可以知道任务是否正确执行完成;我们对异步函数,添加 Future
返回值类型,使用 new AsyncResult<>()
设置回调信息;
@Component
public class Task {
@Async
public Future<String> taskOne() throws Exception {
System.out.println("任务一");
return new AsyncResult<>("任务一执行完成");
}
@Async
public Future<String> taskTwo() throws Exception {
System.out.println("任务二");
return new AsyncResult<>("任务二执行完成");
}
}
测试代码如下, 等待2个任务全部完成后就打印出返回值信息
@Autowired
Task task;
@Test
public void test() throws Exception {
Future<String> str1 = task.taskOne();
Future<String> str2 = task.taskTwo();
while (true){
// 如果任务都做完就执行如下逻辑
if (str1.isDone() && str2.isDone()){
System.out.println(str1.get()+":"+str2.get());
break;
}
}
}
执行输出
任务二
任务一
任务一执行完成:任务二执行完成
关注公众号 知识追寻者 获取原创PDF,面试题集,最新成熟技术栈;
三 线程池
在异步掉用中使用的@Async
注解,默认的线程池大小如下;
# 核心线程数
spring.task.execution.pool.core-size=8
# 最大线程数
spring.task.execution.pool.max-size=16
# 空闲线程存活时间
spring.task.execution.pool.keep-alive=60s
# 是否允许核心线程超时
spring.task.execution.pool.allow-core-thread-timeout=true
# 线程队列数量
spring.task.execution.pool.queue-capacity=100
# 线程关闭等待
spring.task.execution.shutdown.await-termination=false
spring.task.execution.shutdown.await-termination-period=
# 线程名称前缀
spring.task.execution.thread-name-prefix=task-
一般情况下,我们都需要手动创建线程池,使用 ThreadPoolTaskExecutor 类进行配置;这边设置了线程前缀名称,等下测试时就可以判定是否线程池配置成功;
@Configuration
public class PoolConfig {
@Bean
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 设置核心线程数
executor.setCorePoolSize(10);
// 设置最大线程数
executor.setMaxPoolSize(15);
// 设置队列容量
executor.setQueueCapacity(20);
// 设置线程活跃时间(秒)
executor.setKeepAliveSeconds(60);
// 设置默认线程名称
executor.setThreadNamePrefix("zszxz-");
// 设置拒绝策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有任务结束后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
return executor;
}
}
在task类中加上 新的一个方法如下
@Async
public void sayHello(String name) {
LoggerFactory.getLogger(Task.class).info(name + ":Hello World!");
}
使用测试类进行测试
@Test
public void testPool() throws Exception {
task.sayHello("公众号:知识追寻者");
}
执行结果如下,日志打印出线程名称为zszxz-1
;
有时候,一个项目中如果配置了多个线程池,如下格式
@Bean("pool1")
public TaskExecutor taskExecutor1() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//....
return executor;
}
@Bean("pool2")
public TaskExecutor taskExecutor2() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//....
return executor;
}
@Bean("pool3")
public TaskExecutor taskExecutor3() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//....
return executor;
}
在使用 @Async注解时就需要指明具体使用的线程池,如下格式
@Async("pool1")
public void sayHello1(String name) {
LoggerFactory.getLogger(Task.class).info(name + ":Hello World!");
}
@Async("pool2")
public void sayHello1(String name) {
LoggerFactory.getLogger(Task.class).info(name + ":Hello World!");
}
本套教程
- springboot入门 (1)
- Springboot自定义banner(2)
- springboot配置文件解析(3)
- springboot集成mybatis(4)
- springboot集成jdbcTemplate(5)
- spingboot单元测试(6)
- springboot集成thymeleaf(7)
- springboot多文件上传(8)
- springboot文件下载(9)
- Springboot自定义异常类(10)
- springboot多环境配置(11)
- springboot自动配置原理解析(12)
- springboot集成restTemplate接口调用(13)
- springboot集成任务调度(14)
- springboot跨域CORS处理(15)
- springboot开启GIZP压缩(16)
- springboot集成logback(17)
- springboot集成Swagger(18)
- springboot集成actuator后台监控(19)
- springboot集成mybatis+oracle+druid(20)
- springboot 集成springsession(21)
- springboot集成jwt(22)
- springboot集成admin后台监控(23)
- springboot集成redis基础篇(24)
- springboot集成redis缓存篇(25)
- springboot使用AOP日志拦截(26)
- springboot集成Validation参数校验(27)
- springboot集成mybatisPlus(28)
- springboot集成shiro(29)
- springboot实现接口等幂次校验(30)
- springboot-集成WebSockets(31)
- restTemplate源码解析(32)
- SpringBoot使用@Async异步调用与线程池(33)
- 待续
- 待续
源码地址:关注公众号知识追寻者 回复 springboot