同步方法中的@Async 方法 Java
@Async method inside synchronized method Java
为了总结这个问题,我试图在同步方法中调用一些用@async 注释的方法。使用@async 的原因是因为我希望 return post 方法的响应(以减少客户端的等待时间)并继续做一些 post 处理工作(重置某些属性) .但是,由于 POST 方法涉及更改图形数据库,因此我使用 synchronized 关键字声明该方法,以防止在进行另一项计算时更改图形数据库。这样的结果好像是两个线程进入了synchronized方法,这不应该发生?
@RestController
public class Controller {
@PostMapping(path = “/compute”)
public synchronized String compute() {
System.out.println(“===== > In thread: “ + Thread.currentThread().getName());
System.out.print(“===== > Doing some work in compute”);
ResetService.reset()
Return(“===== > done computing”)
}
@Service
public class ResetService {@Async public void reset (){
System.out.println(“===== > resetting in thread: “ + Thread.currentThread().getName());
#(resetting some properties in neo4j graph database)
resetMethod();
System.out.print(“===== > Done Resetting”);
}
这将给我一个类似这样的输出:
===== > 在线程中:http-nio-10080-exec-2
===== > 在计算方面做一些工作
===== > 完成计算
=====> 在线程中重置:Async-1
===== > 在线程中:http-nio-10080-exec-3
===== > 在计算方面做一些工作
===== > 完成重置
我对Synchronized方法的理解是任何时候只允许单线程进入该方法。但是似乎同时有两个线程 运行 同步计算方法。我试图找出一些原因,我能想到的两个主要原因是:
由于 Controller 的不同实例 class,但是我记得在某处读到 RESTController 默认是单例作用域,所以不应该是因为这个?
上下文切换?同步方法是否允许上下文从一个线程切换到另一个线程?
如果我的问题的任何部分令人困惑,我深表歉意,因为我对 Java Spring/Spring Boot 尤其是并发、多线程等概念比较陌生。如果您需要我,请告诉我澄清我问题的任何部分。
当您在同步方法 compute()
中调用异步方法 reset()
时,后者的方法不会等待 reset()
完成。相反,它会生成一个新线程来处理 reset()
的代码执行,然后立即进入下一行 Return(“===== > done computing”)
。之后该方法将完成。当它完成时,将允许新线程调用 compute()
,即使进入 compute()
的前一个线程的 reset()
调用仍在单独的线程中 运行。
所以说的更清楚一点,方法compute()
并不是两个线程同时进入的。它只是看起来那样,因为从线程 http-nio-10080-exec-3
打印的部分文本出现在线程 Async-1
的 Done Resetting
打印之前。所以您的代码按预期工作。
为了总结这个问题,我试图在同步方法中调用一些用@async 注释的方法。使用@async 的原因是因为我希望 return post 方法的响应(以减少客户端的等待时间)并继续做一些 post 处理工作(重置某些属性) .但是,由于 POST 方法涉及更改图形数据库,因此我使用 synchronized 关键字声明该方法,以防止在进行另一项计算时更改图形数据库。这样的结果好像是两个线程进入了synchronized方法,这不应该发生?
@RestController
public class Controller {
@PostMapping(path = “/compute”)
public synchronized String compute() {
System.out.println(“===== > In thread: “ + Thread.currentThread().getName());
System.out.print(“===== > Doing some work in compute”);
ResetService.reset()
Return(“===== > done computing”)
}
@Service
public class ResetService {@Async public void reset (){
System.out.println(“===== > resetting in thread: “ + Thread.currentThread().getName());
#(resetting some properties in neo4j graph database)
resetMethod();
System.out.print(“===== > Done Resetting”);
}
这将给我一个类似这样的输出:
===== > 在线程中:http-nio-10080-exec-2
===== > 在计算方面做一些工作
===== > 完成计算
=====> 在线程中重置:Async-1
===== > 在线程中:http-nio-10080-exec-3
===== > 在计算方面做一些工作
===== > 完成重置
我对Synchronized方法的理解是任何时候只允许单线程进入该方法。但是似乎同时有两个线程 运行 同步计算方法。我试图找出一些原因,我能想到的两个主要原因是:
由于 Controller 的不同实例 class,但是我记得在某处读到 RESTController 默认是单例作用域,所以不应该是因为这个?
上下文切换?同步方法是否允许上下文从一个线程切换到另一个线程?
如果我的问题的任何部分令人困惑,我深表歉意,因为我对 Java Spring/Spring Boot 尤其是并发、多线程等概念比较陌生。如果您需要我,请告诉我澄清我问题的任何部分。
当您在同步方法 compute()
中调用异步方法 reset()
时,后者的方法不会等待 reset()
完成。相反,它会生成一个新线程来处理 reset()
的代码执行,然后立即进入下一行 Return(“===== > done computing”)
。之后该方法将完成。当它完成时,将允许新线程调用 compute()
,即使进入 compute()
的前一个线程的 reset()
调用仍在单独的线程中 运行。
所以说的更清楚一点,方法compute()
并不是两个线程同时进入的。它只是看起来那样,因为从线程 http-nio-10080-exec-3
打印的部分文本出现在线程 Async-1
的 Done Resetting
打印之前。所以您的代码按预期工作。