【发布时间】:2011-01-15 10:45:11
【问题描述】:
如何确保我的 java servlets web 应用程序是线程安全的?对于会话变量、类的静态变量或其他任何可能成为线程安全问题的东西,我需要做什么?
【问题讨论】:
标签: java servlets jakarta-ee
如何确保我的 java servlets web 应用程序是线程安全的?对于会话变量、类的静态变量或其他任何可能成为线程安全问题的东西,我需要做什么?
【问题讨论】:
标签: java servlets jakarta-ee
事实:在 webapp 的生命周期中只有 1 个 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 以获取基本示例。您只需要确保不将纯请求或会话范围的数据放入应用程序范围。
【讨论】:
SingleThreadModel。
【讨论】:
哇,这是一个加载的问题。
简单地说,您需要确保对任何共享数据的访问都经过仔细同步。例如,您可能希望使用互斥锁或同步函数同步对静态变量的访问。
请注意,如果您需要同时修改多个共享资源的原子事务,您可能还需要在更高级别进行同步。
设计一个并发应用程序并不简单,而且没有灵丹妙药(很遗憾)。我强烈推荐《Java Concurrency in Practice》一书,了解有关编写安全并发代码的更多信息。
【讨论】:
您的意思是在上下文中与任何其他 java 应用程序相反?真的没有太大区别。对 servlet 的每个请求都会导致容器发出一个新线程来处理它,因此 servlet 中的实例变量必须是线程安全的。最好使用 doGet / doPost() 方法中的局部变量来处理您的所有业务。我能想到一个问题。对于会话变量,用户可能会打开两个浏览器窗口,它们都指向您的应用程序。在这种情况下,您还需要注意会话范围的线程安全。
【讨论】: