【问题标题】:Is HttpSession thread safe, are set/get Attribute thread safe operations?HttpSession 线程安全吗,设置/获取属性线程安全操作吗?
【发布时间】:2010-10-11 14:57:53
【问题描述】:

另外,被设置的对象是否必须是线程安全的,以保证我们知道存储在会话中的对象的状态是什么。

另外,我在网上阅读了一些建议使用的内容:

synchronized(session) {
  session.setAttribute("abc", "abc");
}

这是一个有效的建议吗?

【问题讨论】:

    标签: java session thread-safety synchronized


    【解决方案1】:

    没有。而且由于您不希望同一个客户端(带有会话)进行并发请求,因此您应该像 AbstractController 在 Spring MVC 中那样序列化这些请求

    【讨论】:

    • 我喜欢这个示例,但对于如何将其用于我的应用程序仍然有些困惑。
    【解决方案2】:

    Servlet 2.5 规范:

    多个 servlet 执行请求 线程可以主动访问 同一个会话对象。 容器必须确保 内部数据操纵 代表会话的结构 属性是在一个 线程安全的方式。开发商有 线程安全的责任 访问属性对象 他们自己。这将保护 里面的属性集合 来自并发的 HttpSession 对象 访问,消除机会 申请导致 集合损坏。

    这是安全的:

    // guaranteed by the spec to be safe
    request.getSession().setAttribute("foo", 1);
    

    这是安全的:

    HttpSession session = request.getSession();
    Integer n = (Integer) session.getAttribute("foo");
    // not thread safe
    // another thread might be have got stale value between get and set
    session.setAttribute("foo", (n == null) ? 1 : n + 1);
    

    保证安全:

    // no guarantee that same instance will be returned,
    // nor that session will lock on "this"
    HttpSession session = request.getSession();
    synchronized (session) {
      Integer n = (Integer) session.getAttribute("foo");
      session.setAttribute("foo", (n == null) ? 1 : n + 1);
    }
    

    我已经看到了最后一种方法被提倡(包括在 J2EE 书籍中),但是 Servlet 规范不能保证它可以工作。你可以use the session ID to create a mutex,但必须有更好的方法。

    【讨论】:

    • 试图理解“容器必须确保对表示会话属性的内部数据结构的操作以线程安全的方式执行”是什么意思。这是否意味着像“tomcat”这样的容器应该确保 getAttribute 和 setAttribute 方法是线程安全的?另外,为什么最后一种方法不能保证有效?
    • @letronje - 这意味着对 getAttribute/setAttribute 的单独调用必须是线程安全的,但对 servlet 没有事务保证。因此,并发使用同一会话可能会导致不一致的状态,除非 servlet 开发人员对此进行保护。
    • @letronje - 最后一种方法要求会话在this 上同步。也就是说,具有public syncrhonized void setAttribute......setAttribute(String s,Object o) { synchronized(this)... 之类的签名。规范不需要这个。一些 servlet 容器会这样做,但不能保证 - 容器如何保护内部状态是一个实现细节。
    • 所以澄清一下,如果同一会话下有两个并行请求,如果一个线程执行 request1.getSession().getAttribute("abc") 另一个线程执行 request2.getSession( ).setAttribute("abc"),这样应该没问题吧?
    • 顺便说一句 - “为什么会话对象上的同步可能不起作用”这个问题的正确答案是请求包装。无法保证您可能会得到什么对象。任何人都可以创建请求包装器,该包装器将返回自己的 HttpSession 实现(例如,一个日志记录或控制集/获取,...)。
    【解决方案3】:

    它们不是,但大多数情况下,您的客户端只会使用单个线程访问它们。

    不同的客户端会有不同的线程,每一个都会有自己的Session。

    正如 Eddie 所指出的,您可能面临两个线程访问同一会话的一种情况是两个 ajax 调用试图修改同一会话属性。否则你不会有问题。

    【讨论】:

      【解决方案4】:

      会话不是线程安全的,get 和 set 方法都不能保证是线程安全的。通常,在 servlet 容器中,您应该假设处于多线程环境中,并且没有提供的工具是安全的。

      这也适用于您存储在会话中的对象。会话本身不会操作存储的对象,但您可以在不同的线程中检索对象并尝试操作它。您可以检查自己的代码以查看是否存在竞争条件。

      您发布的代码示例是有效的,但问题可能存在于您示例的有限范围之外。它确保在设置会话时没有条件,但没有什么可以阻止其他线程覆盖该集合。如果您请求中的代码取决于保持不变的值,您仍然可能遇到麻烦。

      【讨论】:

        【解决方案5】:

        在某些方面,这取决于您的客户端设计。

        在您的网页设计中,您是否有机会让单个客户端使用同一个 HTTP 会话同时处理多个未完成的请求?除非您将单个 HTTP 会话绑定到多个套接字,否则这似乎很难做到。 (又名 AJAX)如果不这样做,就服务器而言,给定客户端的 HTTP 访问将是单线程的,这意味着单个会话实际上是线程安全的。

        会话对象的同步将使应用程序更安全地应对未来的变化,使您的网络应用程序能够同时处理多个请求,所以这不是一个坏主意。在现代 Java 实现中,同步没有以前与之相关的大成本,尤其是当同步通常没有竞争时。如果您的应用程序使用 AJAX,这意味着您希望对 Web 服务器有多个正在进行的同时请求,那么同步是必须的。

        【讨论】:

        • 我只是想为 ajax 请求禁用“synchronizeOnSession”以加快速度(ajax 请求一个接一个地执行,而不是并行执行)。那么这是一个很大的禁忌吗?我认为 ajax 是安全的,因为工作流程通常在 javascript 端进行控制。
        猜你喜欢
        • 2021-11-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-15
        • 2011-07-21
        • 2011-04-01
        • 2016-08-10
        • 1970-01-01
        相关资源
        最近更新 更多