【异步任务】@Async注解使用方法及注解失效解决办法
1. @Async作用范围
@Async
的注解如下,可以看出该注解可以修饰类
和方法
。
@Target({
ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Async {
String value() default "";
}
该注解使用要满足以下基本要求:
- 1)在方法上使用该@Async注解,申明该方法是一个异步任务;(必须是public的方法,不能是private的方法,否则注解会失效!!)
- 2)在类上面使用该@Async注解,申明该类中的所有方法都是异步任务;
- 3)方法上一旦标记了这个@Async注解,当其它线程调用这个方法时,就会开启一个新的子线程去异步处理该业务逻辑。
- 4)使用此注解的方法的类对象,必须是spring管理下的bean对象
(如被@Service、@Component等修饰的Bean对象)
- 5)要想使用异步任务,需要在主类上开启异步配置,即配置上@EnableAsync注解
2. 基本使用方法
2.1 开启异步注解@EnableAsync
在SpringBoot的启动类上开启异步任务注解
@SpringBootApplication
@EnableAsync
public class AsyncDemoApplication {
public static void main(String[] args) {
SpringApplication.run(AsyncDemoApplication.class, args);
}
}
2.2 创建Bean对象及异步方法
@Component
public class Aservice {
@Async
public void MethodA() {
System.out.println("当前线程为:" + Thread.currentThread().getName());
}
}
2.3 在Test方法中进行测试
@SpringBootTest
class AsyncDemoApplicationTests {
@Autowired
private Aservice aservice;
@Test
void contextLoads() {
System.out.println("当前线程名称:" + Thread.currentThread().getName());
aservice.MethodA();
}
}
测试结果如下,可以看到确实开启了一个异步任务。
当前线程名称:main
当前线程为:task-1
2.4 隐藏问题:默认线程池配置不合适,导致系统奔溃
@Async注解在使用时,如果不指定线程池的名称,则使用Spring默认的线程池,Spring默认的线程池为SimpleAsyncTaskExecutor。
该类型线程池的默认配置:
默认核心线程数:8,
最大线程数:Integet.MAX_VALUE,
队列使用LinkedBlockingQueue,
容量是:Integet.MAX_VALUE,
空闲线程保留时间:60s,
线程池拒绝策略:AbortPolicy。
解决方法1: 修改配置文件,指定线程池参数
通过修改SpringBoot的配置文件application.yml
来解决上述问题:
spring:
task:
execution:
thread-name-prefix: MyTask
pool:
max-size: 6
core-size: 3
keep-alive: 30s
queue-capacity: 500
解决方法2:编写配置类
首先在application.yml
文件中自定义一些键值对。
mytask:
execution:
thread-name-prefix: myThread
pool:
max-size: 6
core-size: 3
keep-alive: 30
queue-capacity: 500
然后编写一个集成了AsyncConfig
的配置类
// 如果没有在启动类上加注解,在异步任务配置类中加也是可以的
@EnableAsync
@Configuration
public class AsyncExecutorConfig implements AsyncConfigurer {
@Value(value="${mytask.execution.pool.core-size}")
private String CORE_SIZE;
@Value(value="${mytask.execution.pool.max-size}")
private String MAX_SIZE;
@Value("${mytask.execution.pool.queue-capacity}")
private String QUEUE_SIZE;
@Value("${mytask.execution.thread-name-prefix}")
private String THREAD_NAME_PREFIX;
@Value("${mytask.execution.pool.keep-alive}"