【问题标题】:Spring MVC Rest Services - Number of Threads (Controller Instances)Spring MVC Rest Services - 线程数(控制器实例)
【发布时间】:2016-01-06 15:41:42
【问题描述】:

在我们的应用程序中,我们希望实现更高的吞吐量,所以我只想知道线程在 Spring MVC 控制器中是如何工作的。

提前感谢您的帮助。

这对我有帮助

http://community.jaspersoft.com/wiki/how-increase-maximum-thread-count-tomcat-level

【问题讨论】:

  • 您的 Java EE 服务器(例如 Tomcat)将处理传入请求的线程。一般来说,在 Java Web 应用程序中生成自己的线程并不是一个好主意。
  • 这确实是一个很好的问题,它在谷歌上显示为“spring rest 控制器线程”;我认为没有理由投反对票。考虑到应用服务器和 Spring MVC 的多线程特性,完全清楚这个主题是至关重要的。

标签: java spring spring-mvc


【解决方案1】:

Web 应用程序托管在应用程序服务器(如 tomcat)中。通常应用服务器管理一个线程池,每个请求都由一个线程处理。

Web 应用程序不必担心这个线程池。线程池的大小是应用服务器的一个参数。

实现更高的吞吐量,您确实需要确定瓶颈。

(根据我的经验,应用服务器的线程池大小很少是性能问题的根本原因。)


请注意,“控制器实例的数量”通常为 1。即控制器通常是所有线程共享/使用的单例,因此控制器必须是线程安全的。

【讨论】:

  • 我知道这一点,但只是想知道我是否想在一台服务器上部署两个不同的应用程序,而一个是关键任务,另一个是不是的休息应用程序。我如何控制休息应用程序的线程数。谢谢
【解决方案2】:

让我们再具体说明一下问题:一个感兴趣的应用程序,实现一个 REST 控制器,部署在一个典型的多线程应用程序服务器上(可能还运行其他东西)。问:在处理对控制器映射方法的单独请求时是否存在并发?

我不是这个主题的权威,但它非常重要(特别是:单线程逻辑是否应该应用于 REST-Controller 代码?)。

编辑: 下面的答案是错误的。对同一控制器的不同方法的并发调用同时处理,因此它们使用的所有共享资源(服务、存储库等)必须确保线程安全。然而,出于某种原因,由控制器的相同方法处理的调用被序列化(或者:到目前为止在我看来是这样)。

下面的小测试表明,即使对控制器映射方法的后续(和快速)调用确实由不同的线程处理,单线程逻辑也适用(即没有“开箱即用”的并发性)。

让我们拿控制器:

 AtomicInteger count = new AtomicInteger();

@RequestMapping(value = {"/xx/newproduct"})
@ResponseBody
public Answer newProduct(){
    Integer atCount = count.incrementAndGet();
    ////// Any delay/work would do here
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    Answer ans = new Answer("thread:" + Thread.currentThread().getName() + " controller:" + this, atCount);
    count.decrementAndGet();
    return ans;
}

并启动 10 个快速(几乎并发 w.r.t. 1000 毫秒睡眠时间)REST 请求,例如通过AngularJS 代码

$scope.newProd = function (cnt) {
    var url = $scope.M.dataSource + 'xx/newproduct';
    for(var i=0; i<cnt; ++i) {
        $http.get(url).success(function(data){
            console.log(data);
        });
    }

};

Answer 只带有一个String 和一个Integer;使count 成为静态不会改变任何东西)。发生的情况是,所有请求同时变为pending,但响应按顺序出现,恰好相隔1s,没有atCount&gt;1。它们确实来自不同的线程。

更具体地说,控制台日志具有:

换句话说:

编辑:这表明对相同方法/路由的并发调用被序列化了。但是,通过向控制器添加第二个方法,我们很容易验证,对该方法的调用将与对第一个方法的调用同时处理,因此,用于处理请求的多线程逻辑是强制性的“开箱即用” .

因此,为了从多线程中获利,看起来应该采用传统的显式方法,例如在Executor 上以Runnable 的形式启动任何重要的工作。

【讨论】:

  • 附录:即使睡眠延迟减少到 10、1 甚至 0ms,行为也不会改变。 (在最后一种情况下,我的系统在 5 毫秒内处理了 1000 个这样的简单请求;这是一个单独且非常有趣的问题,例如 10k 请求/秒如何处理......)
  • 我认为是您的客户端(即运行类型脚本的 Web 浏览器)将请求“序列化”到相同的 url。
【解决方案3】:

基本上这与 Spring 无关。通常每个请求都被分叉到一个单独的线程中。所以这里通常要做的就是找到瓶颈。 但是,如果编写不好的 bean 在线程边界上共享状态并因此需要同步,则可能会产生非常糟糕的影响。

【讨论】:

  • 但我想应该有一种方法可以将您的应用程序配置为使用预定义的线程数(最大)。
  • 您在哪里看到将工作委派给不同线程的用例?请求的分叉发生在应用服务器级别(例如 Tomcat),因此应该在那里完成配置。
猜你喜欢
  • 1970-01-01
  • 2016-02-08
  • 2015-07-22
  • 2010-12-15
  • 1970-01-01
  • 2012-07-15
  • 2016-01-22
  • 2021-10-28
  • 2014-12-02
相关资源
最近更新 更多