在Java中,如何确保我的Web应用程序是线程安全的?
如何确保我的java servlets web应用程序是线程安全的?关于会话变量,类的静态变量或其他任何可能成为线程安全问题的事情,我需要做些什么?在Java中,如何确保我的Web应用程序是线程安全的?
事实:这里只有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的基本示例。您只需确保不要将纯请求或会话范围的数据放入应用程序范围中。
您的意思是在上下文中而不是其他任何Java应用程序?真的没有太大的区别。每个对servlet的请求都会导致容器发出一个新线程来处理它,因此servlet中的实例变量必须是线程安全的。最好在doGet/doPost()方法中使用局部变量处理所有商业。有一个我能想到的问题。使用会话变量时,可能会出现这样的情况:用户有两个打开的浏览器窗口,都指向您的应用程序。在这种情况下,您需要注意线程安全性以及会话范围。
哇,这是一个加载的问题。
简而言之,您需要确保对任何共享数据的访问仔细同步。例如,您可能想要使用互斥锁或同步函数来同步对静态变量的访问。
请注意,如果您需要同时修改多个共享资源的原子事务,则可能还需要在较高级别进行同步。
设计一个并发应用程序并不简单,也没有神奇的项目符号(不幸的是)。我强烈推荐编写“Java Concurrency in Practice”这本书,以获取更多关于编写安全并发代码的信息。
有关“在Web应用程序的一生中使用一个servlet”的一个问题 - 我认为这是一个池对象,所以根据负载的不同,servlet引擎可能会有不止一个。这不正确吗? – duffymo 2010-02-10 21:56:15
只有它实现(按照Servlet 2.4弃用)'SingleThreadModel'。 – BalusC 2010-02-10 22:18:03
@BalusC:非常感谢您,先生,这个答案最终帮了我。我删除了我的问题,并提出了你的答案。 Java中没有人喜欢你。再次感谢一百万。 – 2016-06-06 14:30:28