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

在Java中,如何确保我的web应用程序是线程安全的?,java,servlets,jakarta-ee,Java,Servlets,Jakarta Ee,如何确保java servlets web应用程序是线程安全的?对于会话变量、类的静态变量或任何其他可能是线程安全问题的变量,我需要做些什么?您的意思是在上下文中而不是在任何其他java应用程序中?其实差别不大。对servlet的每个请求都会导致容器发出一个新线程来处理它,因此servlet中的实例变量必须是线程安全的。最好在doGet/doPost()方法中使用局部变量处理所有业务。我能想到一个办法。对于会话变量,可能是用户打开了两个浏览器窗口,都指向您的应用程序。在这种情况下,还需要注意会话

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

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

哇,这是一个很难回答的问题

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

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

设计一个并发应用程序并不简单,而且没有灵丹妙药(不幸的是)。关于编写安全并发代码的更多信息,我强烈推荐本书。

  • 不要使用servlet和过滤器的实例变量
  • 不要使用静态变量
  • 思考

事实: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时需要考虑的全部内容

还有session()属性,可以在来自同一用户的多个请求之间共享,但在现实世界中,您实际上不需要担心同步会话访问。您通常只将特定于用户的数据放在那里,例如登录用户、特定于用户的首选项、购物篮等。您只需要确保不会将纯请求范围的数据放入会话范围。它将反映在同一会话中的多个浏览器窗口/选项卡中


还有application()属性,这些属性在应用程序范围内的所有用户之间共享,但通常只在其中放置常量和其他静态数据,如webapp配置、DAO工厂、dropdownlist内容等。顺便说一句,这一切都可以用a来完成,另请参见一个基本示例。您只需确保不会将纯请求范围或会话范围的数据放入应用程序范围。

我认为第4项几乎取代了(涵盖)1-3.:)好吧,在你能好好思考一个关于“web应用生命周期中的一个servlet”的问题之前,需要一些基本知识——我认为这是一个池对象,所以servlet引擎可以根据负载的不同决定不止一个。这不是真的吗?除非它实现了(根据Servlet 2.4弃用)
SingleThreadModel
@BalusC:非常感谢,先生,这个答案最终帮助了我。我删除了我的问题,并对你的答案投了赞成票。在Java中没有人能像你一样。再次感谢你。