【问题标题】:Spring's @Async ignores synchronized?Spring 的 @Async 忽略同步?
【发布时间】:2018-06-24 07:11:58
【问题描述】:

我在服务类中有这个方法:

@Service
public class Service {
    @Async
    public synchronized void asyncTest() {
        try {
            System.out.println("entered");
            Thread.sleep(5000);
            System.out.println("exited");
            System.out.println(this);
        }
        catch (InterruptedException e ) {}
    }
}

当我打电话时

@Test
public void asyncTest() throws InterruptedException {
    service.asyncTest();
    service.asyncTest();
    Thread.sleep(10000);
}

它产生:

entered
entered
exited
exited
...Service@26d74d5f 
...Service@26d74d5f 

虽然我会期待

entered
exited
...Service@26d74d5f 
entered
exited
...Service@26d74d5f 

由于 synchronized 关键字。为什么?

我的xml配置:

<task:annotation-driven mode="aspectj" executor="fisExecutor" scheduler="fisScheduler"/>
<task:executor id="fisExecutor" pool-size="10" />
<task:scheduler id="fisScheduler" pool-size="30" />
<task:executor keep-alive="60" id="cmsExecutor" pool-size="5-00" queue-capacity="0" rejection-policy="CALLER_RUNS"/>

春季版:4.1.9.RELEASE JDK 1.7

测试类注解:

   @RunWith(SpringJUnit4ClassRunner.class)
   @ContextConfiguration(locations = "classpath*:/applicationContext-*.xml")

【问题讨论】:

  • 很可能是因为您停止执行 5 秒。两个方法调用都是异步的,这意味着分开工作。所以他们都在 5s 标记之前打印"entered"
  • service 每次调用 asyncTest() 都会引用同一个对象,对吧?
  • @twinklehawk 是的
  • ...Service@26d74d5f 打印在两个线程中..
  • 我在 JUnit 测试中运行它,但我在完全运行的应用程序中也观察到了这个问题。

标签: java spring asynchronous synchronized


【解决方案1】:

一种方法是更改​​方法签名,以确保您从 API 中获得可控制的异步对象。例如,您可以修改代码以包含 CompletableFutures,模仿如下:

  @Service
  public class Service {
      @Async
      public CompletableFuture<Void> asyncTest() {
          try {
              System.out.println("entered");
              Thread.sleep(5000);
              System.out.println("exited");
              System.out.println(this);
          }
          catch (InterruptedException e ) {}

          return new AsyncResult<Void>(null);
      }
  }

我使用这个网站获取 sn-ps 和调查资源:http://www.baeldung.com/spring-async

【讨论】:

  • 这种方法对于这个例子来说并不理想,但是在一个典型的 API 中,Void 类型可以很容易地被一个实际的对象替换以匹配 API。
  • 我仅限于 jdk 1.7(那里缺少 CompletableFuture)。另外,这能解决同步问题吗?
猜你喜欢
  • 2014-04-28
  • 2017-08-15
  • 1970-01-01
  • 2015-12-10
  • 2023-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-07
相关资源
最近更新 更多