2011-07-01 84 views
2

我目前正在構建一個基於java-servlet的Web應用程序,該應用程序應該向很多用戶提供服務(不要問我有多少「很多」是:-) - 我還不知道)。好或不好主意:基於Java的多用戶基於Servlet的Web應用程序中的多線程

但是,在使用該應用程序時,可能會在服務器端發生一些長時間的處理。 爲了避免錯誤的UI響應,我決定將這些處理操作移到自己的線程中。 這意味着一旦用戶登錄,可能會發生1-10個線程在後臺運行(每個用戶)。

我曾經聽說在Web應用程序中使用多個線程是一個「壞主意」。

這是真的,如果是的話:爲什麼?

更新:我忘了提及我的應用程序嚴重依賴於ajax調用。每個用戶操作都會導致一個新的ajax調用。所以,當主servlet線程忙時,ajax調用需要很長時間才能處理。這就是爲什麼我想要使用多個線程。

+0

爲什麼界面會「凍結」?這聽起來像是你用本地術語思考......在一個Web應用程序中,你應該使用AJAX,否則你會得到一個緩慢的頁面加載,而不是一個「凍結」。 –

+0

我忘了提及我的應用程序嚴重依賴於ajax調用。每個用戶操作都會導致一個新的ajax調用。所以,當主servlet線程忙時,ajax調用需要很長時間才能處理。 – Timo

+0

當然,但這不同於「UI凍結」... –

回答

5

自己手動創建線程是一個壞主意。這在SO中已經討論了很多。例如,請參閱this問題。

另一個question討論替代解決方案。

+0

這對我來說似乎有些過於簡單。不好的想法不僅僅是具有非請求處理線程,而是以不響應服務器關閉或其他生命週期事件的方式創建它們,或者在沒有最大限度上限的情況下產生太多等等。解決方案鏈接到涉及使用Quartz ...在後臺產生線程。唯一的區別是使用一個廣受好評的庫,而不是自己編寫它。 –

+0

你說得對,壞主意是指手動構建線程。我編輯了我的答案。 – kgiannakakis

+0

@matt b @kgiannakakis我注意到大多數備用解決方案都要求我設置最大值。應用程序的線程數。什麼是確定最大值合理值的好方法。我需要的線程數量?我正在運行一個多用戶Web應用程序,我希望大多數用戶能夠產生1-10個線程(也許更多)。我不知道最終會有多少用戶。 – Timo

0

如果應用程序需要它,那麼我說繼續前進並執行後臺線程,但是,由於您不知道將有多少用戶,因此您將面臨極大的風險,導致服務器不堪重負。你可能會考慮一些替代方案,如果它們能適用於你的情況。您是否可以完全離線運行後臺任務,例如在批量工作?你能限制每個登錄用戶需要的線程數嗎?如何將後臺線程的結果返回給用戶?

2

「壞主意」不是多線程。 Java EE最初是這樣編寫的,所以多線程掌握在應用程序服務器的手中,因此用戶不願意啓動自己的線程。

我認爲你真正想要的是對長時間運行的任務進行異步處理,這樣用戶在繼續之前不必等待它們完成。

您可以使用JMS來做到這一點,並保持在Java EE圖畫書中的界限內。我認爲這樣做比較安全,因爲java.util.concurrent包中有新的類和構造。

這仍然不是一件容易的事。多線程代碼不是微不足道的。但我認爲它比以前用Java更容易。

問題的一部分可能是您要求該servlet做太多。 Servlet應該監聽HTTP請求並協調從其他類獲得響應,而不是自己處理所有的處理。也許你的servlet告訴你現在是時候重構一下了。這將有助於您的測試,因爲您可以在不運行servlet/JSP引擎的情況下對這些異步類進行單元測試。

AJAX通過HTTP調用服務不需要阻塞。如果服務可以返回一個令牌,一個聯邦快遞,告訴應用何時以及如何獲得響應,沒有理由不能異步處理該服務。這是您應該隱藏客戶端的服務的實現細節。

0

這主要有三個原因是一個壞主意:

  1. 運行的線程數量過多可以殺死的系統資源,導致一些奇怪的東西,如飢餓和優先級反轉。通常這可以用thread pool來解決。
  2. 用戶會話持續時間不可預知。用戶可以發起一個動作並去喝咖啡,或者他/她可能會抱怨延遲並重做該動作。這可能會導致創建多個後臺作業,因此需要複雜的控制,而當我們討論線程時,我們從不知道如果我們沒有離開競爭條件或未經證實的場景。
  3. 最可能的servlet將與線程有一些交互。現在假設你的應用程序需要擴展,所以你使用了一個集羣容器(畢竟,你有很多用戶)。容器可以鈍化會話並將其恢復到另一個節點。但是你的線程將保留在初始節點中,所以會話和線程之間的鏈接將被打破。這以意外的例外和錯誤500結束 - 服務器故障。

我認爲最好的解決方案是設計你的應用程序,以便它不會創建這麼多的後臺線程。

但是,如果你堅持或真的需要它,請嘗試使用Java EE message driven beans(MDB),並讓你的servlet使用JMS調用它,就像@duffymo所說的那樣。

挑戰在於如何在MDB和用戶會話之間進行通信。也許你的servlet可以創建一個JMS queuetopic並將它發送給MDB以供他們回覆,但我不知道JMS連接的servlet端是否可以被鈍化和恢復。

另一種通信形式是JNDI或外部數據庫或文件,但這需要輪詢,可能無響應或CPU過度。

+0

該servlet不會創建隊列或主題;這是在應用程序啓動之前在應用程序服務器中配置的。 servlet(或更好的服務)將實例化一個將消息發送到隊列或主題的客戶端。 – duffymo

+0

@duffymo關於客戶,當然。實際上,servlet將成爲客戶端。現在對於隊列,JMS允許創建臨時隊列,正如你可以看到[這裏](http://stackoverflow.com/questions/1587231/how-to-create-a-temporary-jms-queue-and-connect-到它按姓名)。 – fernacolo

1

1.
輝煌的想法。
這並不常見,但沒有錯。
如果您認爲需要異步任務以獲得更好的用戶體驗。只要使用它。

2.
你需要小心。
2.1。
創建和銷燬線程會給服務器增加很多開銷。
你最好使用一個執行器,如java.util.concurrent.ThreadPoolExecutor

2.2。
不要只使用Executors.newFixedThreadPool()。這是爲初學者和隱藏危險的細節。
您需要知道ThreadPoolExecutor的邊緣行爲並正確配置它。

  • 多少線程足夠你的任務?你需要計算出來。
  • 如果游泳池中沒有空閒的游泳池會發生什麼?不同的配置可以使其等待,緩存或放棄新任務。你應該期待什麼?
  • 如果任務運行時間過長(如無限循環)會發生什麼情況? java中沒有真正的超時和退出機制。你如何防止這些。
相關問題