在我们的应用程序中,我们希望实现更高的吞吐量,因此我只想知道Spring MVC控制器中的线程如何工作。
提前感谢您的帮助。
这对我有帮助
http://community.jaspersoft.com/wiki/how-increase-maximum-thread-count-tomcat-level
答案 0 :(得分:9)
Web应用程序托管在应用程序服务器(如tomcat)中。通常,应用程序服务器管理线程池,每个请求都由线程处理。
Web应用程序不必担心此线程池。线程池的大小是应用程序服务器的参数。
要实现更高的吞吐量,您确实需要确定瓶颈。
(根据我的经验,应用服务器的线程池大小很少是性能问题的根本原因。)
请注意"控制器实例的数量"通常是一个。即控制器通常是所有线程共享/使用的单例,因此控制器必须是线程安全的。
答案 1 :(得分:3)
让我们再详细说明一个问题:一个感兴趣的应用程序,实现一个REST控制器,部署在一个典型的多线程应用程序服务器上(运行,可能还有其他事情)。问:处理对控制器的映射方法的单独请求是否同时存在?
我不是这个主题的权威,但它非常重要(特别是:应该将单线程逻辑应用于REST控制器代码吗?)。
编辑:以下答案错误。同时处理对同一控制器的不同方法的并发调用,因此它们使用的所有共享资源(服务,存储库等)必须确保线程安全。但是,出于某种原因,通过控制器的相同方法处理的调用被序列化(或者:因此它在我看来如此)。
<击> 下面的小测试表明,即使对控制器的映射方法的后续(和快速)调用确实由不同的线程处理,也应用单线程逻辑(即没有“开箱即用”的cuncurrency)。 击>
让我们拿走控制器:
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. 1000ms睡眠时间)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
,但响应顺序排列,相隔1秒,没有atCount>1
。它们确实来自不同的线程。
编辑:这表明,对相同方法/路径的并发调用是序列化的。但是,通过向控制器添加第二种方法,我们可以轻松验证,对此方法的调用将与对第一种方法的调用同时处理,因此,用于处理请求的多线程逻辑是强制性的“开箱即用” 。
因此,为了从多线程中获利,应该采用传统的显式方法,例如在Runnable
上以Executor
的方式启动任何非平凡的工作。 击>
答案 2 :(得分:0)
基本上这与Spring无关。通常,每个请求都分叉到一个单独的线程中。所以通常要做的就是找到瓶颈。 但是,有可能在线程边界上共享状态并因此需要同步的写得很糟糕的bean可能会产生非常糟糕的影响。