2015-10-08 58 views
1

在我們的應用程序中,我們希望獲得更高的吞吐量,所以我只想知道線程在Spring MVC控制器中的工作方式。Spring MVC Rest Services - 線程數(控制器實例)

在此先感謝您的幫助。

幫我

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

+0

您的Java EE服務器(例如Tomcat)將處理傳入請求的線程。一般來說,在Java Web應用程序中產生自己的線程並不是一個好主意。 – GriffeyDog

+1

這真的是一個很好的問題,它在谷歌上顯示「春天休息控制器線程」高;我認爲沒有理由贊成降薪。考慮到應用程序服務器和Spring MVC的多線程特性,對此主題進行全面清晰至關重要。 –

回答

7

Web應用程序是託管在應用程序服務器(如tomcat)中。通常,應用程序服務器管理一個線程池,每個請求都由一個線程處理。

Web應用程序不必擔心此線程池。線程池的大小是應用程序服務器的參數。

實現更高吞吐量您確實需要確定瓶頸。

(根據我的經驗,應用程序服務器的線程池的大小是很少的性能問題的根本原因。)


注意「控制器實例的數量」是正常的。即控制器通常是所有線程共享/使用的單例,因此控制器必須是線程安全的。

+0

我知道這一點,但只是想知道如果我想在一臺服務器上部署兩個不同的應用程序,而一個是關鍵任務,另一個是其餘的應用程序沒有。我如何控制休息應用程序的線程數。謝謝 – DhruvG

0

基本上,這無關與Spring。通常每個請求都分成一個單獨的線程。所以通常要做的就是找到瓶頸。 但是,在線程邊界上共享狀態並因此需要同步的寫入不良的bean可能會產生非常糟糕的影響。

+0

但我想應該有一種方法來配置您的應用程序使用預定義數量的線程(最大)。 – DhruvG

+1

你在哪裏看到將工作委託給不同線程的用例?請求的分叉發生在應用程序服務器(例如Tomcat)的級別,因此應該在那裏進行配置。 – hotzst

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只是攜帶StringInteger;使count靜態不會改變任何東西)。會發生什麼情況,所有請求都會同時變爲pending,但響應會按順序排列,相隔1秒,而且沒有任何響應請求atCount>1。他們確實來自不同的線程。

更具體控制檯日誌具有: enter image description here

換句話說

enter image description here

編輯:這表明,要併發呼叫相同的方法/路由序列化。但是,通過向控制器添加第二種方法,我們可以輕鬆驗證,對此方法的調用將與對第一個方法的調用同時處理,因此用於處理請求的多線程邏輯是強制性的「開箱即用」 。

因此,爲了從多線程中獲利,人們應該採用傳統的顯式方法,例如在 Executor上使用 Runnable來啓動任何非平凡的工作。

+0

附錄:即使睡眠延遲減少到10,1或甚至0ms,行爲也不會改變。 (在最後一種情況下,我的系統在5毫秒內處理1000個這樣的簡單請求;它是一個單獨的且非常有趣的問題,我們如何去做,比如10k個請求/秒......) –