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

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

事实:在webapp的生命周期中,只有一个servlet实例。 它在webapp的启动时创建,并在webapp关闭时被销毁。 另请参阅此答案以获得粗略的解释。

因此,它在所有请求(线程)之间共享。 如果您将请求或会话范围数据分配为实例(或者更糟,更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完成,也可以看一下这个答案的基本示例。 您只需确保不将纯请求或会话范围的数据放在应用程序范围中。

  • 不要使用servlet和filter的实例变量
  • 不要使用静态变量
  • 阅读本文关于会话线程安全性
  • 认为

哇,这是一个有问题的问题。

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

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

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

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