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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24898547/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 15:26:33  来源:igfitidea点击:

Spring async method called from another async method

javamultithreadingspringasynchronousspring-4

提问by spauny

I'm using Spring 4 and I've noticed an odd behaviour... if I'm calling an async method multiple times from a normal instance method then they are all called in different threads and finish at random times. But if I call multiple times an async method from another async method then they finish in order. I have something like this:

我正在使用 Spring 4,我注意到一个奇怪的行为......如果我从一个普通的实例方法多次调用一个异步方法,那么它们都会在不同的线程中被调用并随机完成。但是如果我从另一个异步方法多次调用一个异步方法,那么它们会按顺序完成。我有这样的事情:

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

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

I'm using the default async executor. Should I use a different one? However this executor do not reuse any threads and starts another one every time so it should be fine... Can it be just a coincidence? But I've tried like more than 10 times and if I revert back to non-async for the first method then they finish randomly

我正在使用默认的异步执行器。我应该使用不同的吗?但是这个执行器不会重用任何线程并且每次都启动另一个线程所以应该没问题......这只是巧合吗?但是我已经尝试了 10 多次,如果我恢复到第一种方法的非异步,那么它们会随机完成

采纳答案by geoand

What you are describing is a classic pitfall of Spring AOP.

您所描述的是 Spring AOP 的一个经典陷阱。

In short, for Spring to be able to provide the async behavior it needs to create a proxy for your class at runtime. The proxy then does whatever it needs to do before and/or after calling your code. But in your case, the proxy mechanism is not being applied for the second method.

简而言之,为了让 Spring 能够提供异步行为,它需要在运行时为您的类创建代理。代理然后在调用您的代码之前和/或之后执行它需要执行的任何操作。但是在您的情况下,代理机制并未应用于第二种方法。

When a bean of your class is injected via Spring into some other component, Spring really injects the proxy instead. Therefor the relevant method of the proxy is called. However, when you are calling a method from inside the class, the limitations of Spring AOP mean the proxy never comes into play, but instead the regular method is called - with no extra features.

当您的类的 bean 通过 Spring 注入其他组件时,Spring 实际上会注入代理。因此调用代理的相关方法。但是,当您从类内部调用方法时,Spring AOP 的限制意味着代理永远不会发挥作用,而是调用常规方法 - 没有额外的功能。

That is why asyncMethodis always executing on the same thread as the other method in the same class that called it.

这就是为什么asyncMethod总是在与调用它的同一个类中的另一个方法相同的线程上执行。

Check out thisexcellent blog post as well as thispart of Spring documentation.

查看这篇优秀的博客文章以及Spring 文档的这一部分。

There are some ways around the problem (check out this) that don't require you to refactor your code, but if you want async to work on both methods no matter what, the simplest thing to do is refactor the second method into another class.

有一些方法可以解决这个问题(看看这个),不需要你重构你的代码,但是如果你无论如何都希望异步在这两种方法上工作,最简单的方法就是将第二种方法重构到另一个类中.