赞
踩
使用步骤:
EnableAsync
注解开启异步@Async,也可以直接在类上加此注解,会标识所有方法为异步方法
如下方式会使@Async失效
异步方法使用static修饰
异步类没有使用@Component注解(或其他注解)导致spring无法扫描到异步类
异步方法不能与被调用的异步方法在同一个类中
类中需要使用@Autowired或@Resource等注解自动注入,不能自己手动new对象
如果使用SpringBoot框架在启动类或配置类中增加@EnableAsync注解
线程池参考链接: https://www.bbsmax.com/A/8Bz8QWwXJx/
工作中经常涉及异步任务,通常是使用多线程技术,比如线程池ThreadPoolExecutor,但使用Executors容易产生OOM,需要手动使用ThreadPoolExecutor创建线程池;在springboot使用 @async 可以实现异步调用,配置线程池参数,可以简单的实现多线程的线程池效果,从而简化开发,避免OOM;
我们知道同步执行就是按照代码的顺序执行,而异步执行则是无序,在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();
- }
如果按照同步执行逻辑会先执行任务一,然后再执行任务二,如果是异步执行,则无序,可能任务一先执行,也可能任务二先执行;
有时候要知道任务是否执行完成,再继续做其它的业务逻辑,就需要使用到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;
- }
- }
- }
执行输出
- 任务二
- 任务一
- 任务一执行完成:任务二执行完成
在异步掉用中使用的@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!");
- }
源码地址:https://github.com/zszxz/study-springboot
参考链接:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。