在Java中,如何确保我的Web应用程序是线程安全的?

时间:2010-02-10 20:08:44

标签: java servlets java-ee

如何确保我的java servlet Web应用程序是线程安全的?关于会话变量,类的静态变量或其他任何可能是线程安全问题的问题,我需要做些什么?

4 个答案:

答案 0 :(得分:21)

事实:在webapp的生命周期中,只有一个servlet实例。它在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.
    } 
}

在开发具有线程安全性的servlet时,基本上只需要考虑这一点。

然后会话(HttpSession)属性可以在同一用户的多个请求之间共享,但在现实世界中,您实际上不需要担心同步会话访问。您通常只在那里放置用户特定的数据,例如登录用户,用户特定的偏好,购物篮等。您只需确保不将纯请求范围数据放在会话范围中。它会反映在同一会话中的多个浏览器窗口/标签中。

然后有应用程序(ServletContext)属性在应用程序范围内的所有用户之间共享,但您通常只放置常量和其他静态数据,如webapp配置,DAO工厂,下拉列表内容等。这一切都可以通过ServletContextListener来完成,另请参阅this answer作为基本示例。您只需要确保不要将纯请求或会话作用域数据放在应用程序范围内。

答案 1 :(得分:16)

答案 2 :(得分:1)

哇,这是个问题。

简而言之,您需要确保仔细同步对任何共享数据的访问。例如,您可能希望使用互斥锁或同步函数同步对静态变量的访问。

请注意,如果您需要同时修改多个共享资源的原子事务,您可能还需要在更高级别进行同步。

设计并发应用程序并不简单,并且没有灵丹妙药(不幸的是)。我强烈推荐这本书“Java Concurrency in Practice”,以获取有关编写安全并发代码的更多信息。

答案 3 :(得分:0)

你的意思是在上下文中,而不是任何其他Java应用程序?确实没有太大区别。对servlet的每个请求都会导致容器发出一个新线程来处理它,因此servlet中的实例变量必须是线程安全的。最好在doGet / doPost()方法中使用局部变量处理所有业务。有一个我能想到的问题。对于会话变量,可能会出现用户打开两个浏览器窗口的情况,这两个窗口都指向您的应用程序。在这种情况下,您还需要注意会话范围的线程安全性。