Spring @Async导致程序卡死分析

问题描述:

项目测试中,未发现问题,后面压测同学进行压测发现程序只执行部分交易,后面的交易都卡在第一步了,CPU、内存、GC都正常。

问题定位:

通过arthas定位发现线程卡在((Spring 5.1.16版本)AsyncExecutionInterceptor 117行,最终是FutureTask的get()方法)。

问题原因:

代码中同时使用了PROXY和ASPECTJ两种代理,先走PROXY代理(在拦截器中走进了异步),后面进入到真正的业务方法,然后走进了ASPECTJ代理(这是编译时代理),这里也会获取线程池中的线程

解决方案:

  1. 去除Future返回值,前提是程序不需要返回值的情况
  2. 去除PROXY、ASPECTJ代理中,其中一个代理
  3. @EnableAsync中的mode,建议统一用一种

 注意事项

  1. 程序中使用了ASPECTJ代理,但是没有让spring容器去管理,导致AnnotationAsyncExecutionAspect的beanFactory为空,此时会有两种情况:
    1. Async(有值),会抛异常
    2. Async(无值),此时没有拿到线程池,不会开启新的线程,会在当前线程中继续执行

代码执行流程

  1. 启动项目

2.程序启动成功,发起http请求

 通过堆栈信息可以看出程序首先进入了jdk动态代理类

 这里开启了异步

进入到业务方法

 可以发现此时业务方法已经被代理(AspectJ静态代理)

会调用下面的方法

这里会开启异步

最终在最后一行代码上打上端点,查看线程,可以发现一次请求占用两个线程

结论:当交易密集的时候,线程来不及释放,最终导致线程耗尽。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值