2010-02-10 123 views

回答

21

事實:這裏只有1中的servlet實例在Web應用程序的一生。它在webapp的啓動時創建,並在webapp關閉時被破壞。另請參閱this answer進行粗略解讀。

因此,它已在所有請求(線程)之間共享。如果將請求或會話作用域數據作爲實例(或更糟糕的話,作爲static)變量,那麼它絕對不是線程安全的,因爲它在應用程序範圍內的所有用戶(會話)的所有請求(線程)之間共享。您只需將它們分配爲方法局部變量,以使它們保持線程安全。所以:

public class MyServlet extends HttpServlet { 

    private Object thisIsNOTThreadSafe; 

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
     Object thisIsThreadSafe; 

     thisIsNOTThreadSafe = request.getParameter("foo"); // BAD!! Shared among all requests! 
     thisIsThreadSafe = request.getParameter("foo"); // OK, this is thread safe. 
    } 
} 

這基本上是您在開發考慮thread安全性的servlet時需要考慮的全部內容。

然後會話(HttpSession)屬性可以在同一用戶的多個請求之間共享,但在現實世界中,您實際上並不需要擔心同步會話訪問。您通常只將用戶特定的數據放在那裏,例如登錄用戶,用戶特定偏好,購物籃等等。您只需確保不要將純請求範圍數據放入會話範圍中。它會反映在同一個會話中的多個瀏覽器窗口/選項卡中。

然後,應用程序(ServletContext)屬性在所有用戶的應用程序範圍內共享,但通常只在其中放置常量和其他靜態數據,如web應用程序配置,DAO工廠,dropdownlist內容等。這一切都可以通過ServletContextListener完成,也可以參考this answer的基本示例。您只需確保不要將純請求或會話範圍的數據放入應用程序範圍中。

+0

有關「在Web應用程序的一生中使用一個servlet」的一個問題 - 我認爲這是一個池對象,所以根據負載的不同,servlet引擎可能會有不止一個。這不正確嗎? – duffymo 2010-02-10 21:56:15

+0

只有它實現(按照Servlet 2.4棄用)'SingleThreadModel'。 – BalusC 2010-02-10 22:18:03

+0

@BalusC:非常感謝您,先生,這個答案最終幫了我。我刪除了我的問題,並提出了你的答案。 Java中沒有人喜歡你。再次感謝一百萬。 – 2016-06-06 14:30:28

0

您的意思是在上下文中而不是其他任何Java應用程序?真的沒有太大的區別。每個對servlet的請求都會導致容器發出一個新線程來處理它,因此servlet中的實例變量必須是線程安全的。最好在doGet/doPost()方法中使用局部變量處理所有商業。有一個我能想到的問題。使用會話變量時,可能會出現這樣的情況:用戶有兩個打開的瀏覽器窗口,都指向您的應用程序。在這種情況下,您需要注意線程安全性以及會話範圍。

1

哇,這是一個加載的問題。

簡而言之,您需要確保對任何共享數據的訪問仔細同步。例如,您可能想要使用互斥鎖或同步函數來同步對靜態變量的訪問。

請注意,如果您需要同時修改多個共享資源的原子事務,則可能還需要在較高級別進行同步。

設計一個併發應用程序並不簡單,也沒有神奇的項目符號(不幸的是)。我強烈推薦編寫「Java Concurrency in Practice」這本書,以獲取更多關於編寫安全併發代碼的信息。

16
+2

我認爲項目4非常取代(涵蓋)1-3。 :) – 2010-02-10 20:20:23

+3

好吧,需要一些基本的知識,然後才能做出一些好的想法 – Bozho 2010-02-10 20:23:54

+0

對於第4項而言+1 :) – BalusC 2010-02-10 20:48:48