问题场景:系统中@Scheduled设置的定时任务每两分钟执行一次,某一天上线了后发现@Scheduled不按时执行,经过排查发现是Spring内部某些内容共用了默认线程池,导致线程池资源不够而抢占资源导致。当时上线的是Kafka内容,引用了spring-kafka,经查发现其使用的线程池和@Scheduled是相同的默认线程池所以出现的问题,Kafka的大量并发持续占满线程池,导致定时任务抢占不到。
文章目录
下面是对@Async的源码进行分析为例,分析下线程池的创建过程。对源码不感兴趣的,可以跳到最后看解决这个问题的方法代码。
源码分析过程
@EnableAsync开启spring异步执行器,需要联合@Configuration注解一起使用
@Async该注解可以标记一个异步执行的方法,也可以用来标注类,表示类中的所有方法都是异步执行的。
@Async
*注意:@Async如果A类的A.a()方法调用同类的`@Async A.b()`方法异,会变成同步,因为底层实现是代理对注解扫描实现的,A.a()方法上没有注解,没有生成相应的代理类*返回值:void或AsyncResult或CompletableFuture
可以自己指定执行器的beanName: @Async(“xxxExecutor”)
@EnableAsync
直接看源码注释,解释的很清楚,重要的内容有下面这些(其它点在另一篇详细解析中介绍)
- 搭配@Configuration一起使用
- 默认Spring会寻找已经定义的线程池,已定义的
org.springframework.core.task.TaskExecutor实例或名称为taskExecutor的实例,如果都没有则会用org.springframework.core.task.SimpleAsyncTaskExecutor。 默认异步的异常只会打印日志 - 想自定义线程池或者异常捕获可以通过实现
AsyncConfigurer来实现,如下
@Configuration
@EnableAsync
public class AppConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(7);
executor.setMaxPoolSize(42);
executor.setQueueCapacity(11);
executor.setThreadNamePrefix("MyExecutor-");
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new MyAsyncUncaughtExceptionHandler();
}
}
@EnbaleAsync的属性annotation
定义需要被扫描的注解,默认的Spring的
@Async和EJB的@javax.ejb.Asynchronous注解会被扫描,用户可以通过这个属性设置自定义的注解来被扫描为异步类或方法
@Import(AsyncConfigurationSelector.class)
public @interface EnableAsync {
Class<? extends Annotation> annotation() default Annotation.class;
... ...
}
如果你了解SpringBoot的自动装配原理,就知道看这类源码一眼看到就是@Import(AsyncConfigurationSelector.class)
AsyncConfigurationSelector
@Override
@Nullable
public String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
// EnableAsync中`AdviceMode mode() default AdviceMode.PROXY;`
case PROXY:</

本文探讨了Spring中@Scheduled定时任务与@Async异步执行器的并发问题,由于默认线程池资源不足,导致定时任务无法按时执行。问题源于spring-kafka的并发占用。分析了@EnableAsync的配置和线程池选取过程,包括AsyncAnnotationBeanPostProcessor、AsyncConfigurationSelector等。解决方法是为@Async和@Scheduled配置独立的线程池。
最低0.47元/天 解锁文章
167

被折叠的 条评论
为什么被折叠?



