Java Spring Boot MVC控制器是多线程的吗?

Java Spring Boot MVC控制器是多线程的吗?,java,multithreading,spring-mvc,spring-boot,Java,Multithreading,Spring Mvc,Spring Boot,我是SpringMVC的新手,我在doc中没有找到任何关于这方面的信息。 假设我有一个控制器/帐户,它接受POST请求来创建帐户。 两个请求(几乎)以相同的帐户id同时出现。 ASFAIKdispatcherServlet管理请求 在第一个请求完成之前,是否将第二个请求放入队列? 或者会有两个线程同时处理两个请求 更新: 查看官方的Spring教程:。 有一个控制器,其方法为添加 @RequestMapping(method = RequestMethod.POST) ResponseEntit

我是SpringMVC的新手,我在doc中没有找到任何关于这方面的信息。 假设我有一个控制器/帐户,它接受POST请求来创建帐户。 两个请求(几乎)以相同的帐户id同时出现。 ASFAIK
dispatcherServlet
管理请求

在第一个请求完成之前,是否将第二个请求放入队列? 或者会有两个线程同时处理两个请求

更新: 查看官方的Spring教程:。 有一个控制器,其方法为添加

@RequestMapping(method = RequestMethod.POST)
ResponseEntity<?> add(@PathVariable String userId, @RequestBody Bookmark input) {
    this.validateUser(userId);
    return this.accountRepository
            .findByUsername(userId)
            .map(account -> {
                Bookmark result = bookmarkRepository.save(new Bookmark(account,
                        input.uri, input.description));

                HttpHeaders httpHeaders = new HttpHeaders();
                httpHeaders.setLocation(ServletUriComponentsBuilder
                        .fromCurrentRequest().path("/{id}")
                        .buildAndExpand(result.getId()).toUri());
                return new ResponseEntity<>(null, httpHeaders, HttpStatus.CREATED);
            }).get();

}
同时,第二个线程刚刚执行

Bookmark result = bookmarkRepository.save(new Bookmark(account,
                    input.uri, input.description));
在这种情况下,第一个线程将返回第二个线程创建的
result.getId()).toUri()


这是正确的工作流吗?此控制器线程安全吗?

对于该类型的所有框架,可以安全地假设将同时处理控制器方法(即在多个并发线程中)。此外,以任何其他方式实现这一点都会对性能造成严重影响(是的,有些框架的设计与最初的设计非常不同,但我们现在不讨论这些)

Spring本身无法知道URL的帐户id部分在某种程度上是特殊的,需要在其上进行同步。如果它在URL级别进行同步,将使性能下降到爬网。您始终可以自己实现此逻辑,例如,在该控制器方法操作的会话作用域对象上进行同步(或按照建议使整个控制器会话作用域化)。然后,这将仅序列化该用户(该HTTP会话)的调用。如果希望在所有用户之间同步,可以使用全局共享锁,但出于上述原因,这是一个非常糟糕的主意

相反,在设计应用程序时,所有控制器都是完全无状态的,如果可能的话,使方法要么是幂等的,要么具有正确的前提条件检查逻辑。如果该方法正在写入数据库,则可以实现乐观锁定策略。Hibernate已经有了这一特性,一些DBs/驱动程序也有这一特性,所以请研究哪些特性适用于您的情况

更新


在提供的示例中,两个线程都在保存一个实例(我假设save意味着根据需要插入/更新),返回的对象是当前save操作的结果,因此没有奇怪的线程间行为。这是假设save是事务性的,具有合理的事务隔离级别(其他任何一种假设都是非常不寻常的)。实际上,第二个线程只会覆盖第一个线程编写的值,但这可能是您所期望的。这就是说,您只读取了下一行中的id,这可能永远不会改变,因此URL构建似乎不会受到并发性的影响。

大多数servlet会为每个传入请求启动单独的线程,Spring也不例外。您需要确保共享bean是线程安全的。否则,剩下的就交给春天了

问题的解决方案可能是:

  • 用@Scope(“请求”)或@Scope(“会话”)注释控制器
  • 将私有变量移动到其中一个方法中,或将其保存在会话或模型中

  • 我是从

    获得的,如果控制器有状态,则会出现线程问题。但是它没有。这里所有的操作都是局部变量,每个线程都有自己的非共享局部变量。一个线程不可能看到另一个线程的局部变量。
    Bookmark result = bookmarkRepository.save(new Bookmark(account,
                        input.uri, input.description));