子线程调用@Async方法问题

项目需要在启动后死循环处理队列中的任务,具体的处理方法是异步的。之前的做法是在子线程中执行@Async方法,一直有两个奇怪的现象:

  1. 会出现明明线程池里还有线程,@Async方法却不执行了。
  2. 配置的线程数总比真实使用的多一个。

针对第一个现象:
定位到是因为线程池的拒绝策略导致的, 原来的配置是CallerRunsPolicy.

JDK 提供了四种内置拒绝策略,我们要理解并记住,有如下的四种:
1、DiscardPolicy: 默默丢弃无法处理的任务,不予任何处理
2、DiscardOldestPolicy: 丢弃队列中最老的任务, 尝试再次提交当前任务
3、AbortPolicy: 直接抛异常,阻止系统正常工作。
4、CallerRunsPolicy: 将任务分给调用线程来执行,运行当前被丢弃的任务,这样做不会真的丢弃任务,但是提交的线程性能有可能急剧下降。
将拒绝策略改为默认的即可.

针对第二个问题:
经过深入调查发现@Async方法被调用时会取线程执行器,通过子线程完成异步调用。如果没有线程执行器则直接调用getExecutorQualifier()获取,所以如果是在子线程中调用的@Async方法,会取子线程所在的线程池中的线程。所以此时无论是ThreadPoolTaskExecutorExecutor结果都会导致配置的最大线程数少了一个。
所以,不要在子线程中调用@Async方法

详细代码可以跟一下AsyncExecutionAspectSupport这个类里的determineAsyncExecutor()

determineAsyncExecutor.png

搞清楚原理解决就很容易了,将死循环换到ApplicationListener中,在项目启动完成后执行,不再使用子线程即可解决。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容