另一个异步方法调用的Spring异步方法

34

我正在使用Spring 4,发现一个奇怪的现象... 如果我从普通实例方法中多次调用异步方法,则所有调用都在不同的线程中运行,并且以随机时间完成。但是,如果我从另一个异步方法中多次调用异步方法,则它们按顺序完成。我有类似以下代码:

@Async
public void nonAsyncMethod() {
  for (int i = 0; i < 30; i++) {
     asyncMethod();
  }
}

@Async
public void asyncMethod() {
   ... something here
}

我正在使用默认的异步执行程序。我应该使用其他的吗?但是这个执行程序不会重用任何线程,并且每次都会启动另一个线程,所以应该没问题...这只是巧合吗?但我尝试了超过10次,如果我将第一个方法恢复为非异步,则它们会随机完成。


1
如果第一个异步方法调用了一个调用第二个异步方法(多次)的非异步方法,会怎么样? - ZhongYu
1个回答

77
您所描述的是Spring AOP的一个典型陷阱。 简而言之,为了使Spring能够提供异步行为,它需要在运行时为您的类创建代理。然后代理在调用您的代码之前和/或之后执行其需求。但在您的情况下,第二个方法并没有应用代理机制。
当通过Spring将您的类的bean注入到某些其他组件中时,Spring实际上注入代理而不是原始对象。因此,调用代理的相关方法。 但是,当您从类内部调用方法时,Spring AOP的限制意味着代理永远不会发挥作用,而是调用常规方法-没有额外功能。
这就是为什么`asyncMethod`总是在与调用它的同一类中的其他方法上执行相同的线程的原因。
查看此优秀的博客文章以及Spring文档的这一部分,了解解决问题的一些方法。
有一些绕过问题的方法(请参阅此处),无需重构代码即可使用,但如果您想让异步在两种方法中都起作用,则最简单的方法是将第二个方法重构为另一个类。

@KarthikR 很高兴你喜欢它!谢谢! - geoand
这是一个很棒的答案!有什么简单的技巧可以轻松克服吗? - Amanuel Nega
@AmanuelNega 最简单的解决方案通常是将该方法重构到另一个类中(当然,该类也需要成为Spring bean)。 - geoand

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接