在Springboot的启动类上加上
@EnableAsync
之后就可以在方法使用@Async就可以异步的调用该方法。
发现当前同一个类中调用带有@Async注解的方法,该方法并未采用异步的方式运行,而是同步。
结论:
在定义异步方法的同一个类中,调用带有@Async注解方法,无法以异步的方式运行该方法。
解决:在需要异步调用该方法时候,请在其他的类中调用。
实验
如定义一个调用带有@Async注解的方法
@Component
public class AsyncTask {
private static final Logger logger = LoggerFactory.getLogger(AsyncTask.class);
public void synCall() throws InterruptedException {
logger.info("syn method Call task1 start ...");
task1();
logger.info("syn method Call task1 end");
}
@Async
public void task1() throws InterruptedException {
logger.info("task1 start ...");
logger.info("Sleep {}s", 3);
TimeUnit.SECONDS.sleep(3);
logger.info("task1 end");
}
}
@Autowired
private AsyncTask asyncTask;
@Test
public void testSyncTask() throws InterruptedException {
// 同步调用
asyncTask.synCall();
}
输出
2019-03-03 13:56:59.316 [ main] : syn method Call task1 start ...
2019-03-03 13:56:59.316 [ main] : task1 start ...
2019-03-03 13:56:59.316 [ main] : Sleep 3s
2019-03-03 13:57:02.316 [ main] : task1 end
2019-03-03 13:57:02.316 [ main] : syn method Call task1 end
从上面的日志中可以发现所有日志打印都在主线程中,在打印了Sleep 3s之后,main线程睡眠了3秒之后才继续打印synCall()方法的 syn method Call task1 end。说明这段@Async注解并未生效。
在测试类中直接调用异步方法
@Test
public void testAsyncTask() throws InterruptedException {
// 异步调用
logger.info("Call from other class start...");
asyncTask.task1();
logger.info("Call from other class end");
// 防止由于主线程提前结束,导致异步的线程被强制停止,让主线程睡眠
TimeUnit.SECONDS.sleep(5);
}
注意:如果没有使用
TimeUnit.SECONDS.sleep()使主线程睡眠,我们会因为主线运行结束之后导致异步任务的线程也结束,最后会发现没有异步任务线程的输出。
输出
2019-03-03 14:05:01.052 [ main] : Call from other class start...
2019-03-03 14:05:01.057 [ main] : Call from other class end
2019-03-03 14:05:01.062 [cTaskExecutor-1] : task1 start ...
2019-03-03 14:05:01.063 [cTaskExecutor-1] : Sleep 3s
2019-03-03 14:05:04.063 [cTaskExecutor-1] : task1 end
从上面的结果中可以发现,测试中的task1()是在main线程睡眠之后才被调用,并且从日志中可以发现运行task1()的线程为cTaskExecutor-1,说明该方法缺失以异步的方式运行。
原因分析
我们分别对两种方式进行BUG调试,观察他们的调用栈。

首先是@Async不生效的调用栈

@Async生效的调用栈

通过观察我们可先发现 @Async不生效 的调用栈中非常简单和直接一个条链路直接到断点处,在 @Async生效 的调用栈中,我系清晰的看Spring使用AOP机制在运行
也就是说 @Async不生效 是应为为AOP并没有生效,至于他为什么不生效,我们可以通过AOP的机制和织入点来判断,由于笔者能力有限,希望有人能够补充该疑问,谢谢。
本文详细解析了SpringBoot中@Async注解的使用场景与限制,指出在同一类中调用@Async方法将不会异步执行,而需在其他类中调用才能实现异步效果。

8947

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



