0

在我们的 Web 应用程序中测试并发访问时,我们在跟踪会话行为时遇到了一些困难。

假设我们有三个不同的用户,A、B 和 C。

我们正在使用这三个用户使用三个不同的浏览器登录应用程序,然后在运行时我的用户对象从 B 更改为 A 或 B 更改为 C 或 C 更改为 A,但这是随机发生的。

我的 UserContextHolder 类是:

public final class UserObjContextHolder {
    private static final ThreadLocal<UserObj> CONTEXT_HOLDER = new ThreadLocal<UserObj>();

    private UserObjContextHolder() {
    }

    public static void setUserObj(UserObj userObj) {
        CONTEXT_HOLDER.set(userObj);
    }

    public static UserObj getUserObj() {
        return CONTEXT_HOLDER.get();
    }

}

我正在为 ORM 和 Spring MVC 使用 Hibernate

谁能告诉我此会话行为的原因或如何同步它?

我注意到一件事:如果用户 A 已登录并执行一些搜索操作,并且如果用户 B 同时登录,则 userObj A 将更改为 userObj B。

它与应用程序服务器设置有关吗?这仅在进行身份验证时发生。

4

1 回答 1

2

我想更多地了解您是如何执行搜索操作的,以及您在什么时候在 ThreadLocal 对象 (CONTEXT_HOLDER) 中设置了 UserObj。

我们必须记住 ThreadLocal 是线程范围的,而不是会话范围的。这意味着当且仅当设置对象的线程与请求它的线程相同时,ThreadLocal 中的设置对象是相同的。

我最初的理论是搜索操作在同一个会话中执行,但不在同一个线程上。一个简单的场景如下:

  • UserA 使用线程 A 登录。UserA 使用线程 A 存储在 CONTEXT_HOLDER 中。
  • UserB 使用线程 B 登录。UserB 使用线程 B 存储在 CONTEXT_HOLDER 中。
  • UserC 使用线程 C 登录。UserC 使用线程 C 存储在 CONTEXT_HOLDER 中。
  • 一段时间后,UserA 执行搜索操作。服务器使用线程 A 执行操作(幸运的是)。 ThreadLocal 返回正确且预期的 UserA obj!
  • 又过了一会儿,用户 A 执行搜索操作。这一次,(不幸的是)服务器使用线程 C 执行操作(呃-哦!)。ThreadLocal 将返回 UserC,因为 Thread C 用于执行搜索操作。(另一方面,如果在搜索操作中使用了 Thread B,则 ThreadLocal 将返回 UserB)

上面的场景被过度简化了,假设服务器只使用了三个线程。但我确实希望它能解释您如何获得不同的 UserObj 对象。如果我上面描述的是您所遇到的情况,我认为您也会不时收到 NULL 值(遇到这种情况的频率取决于服务器使用的总线程数)。原因是 ThreadLocal 如果当前未设置,则返回初始值(根据您上面的代码为 null)。

因此,解决您的问题的方法是确保您在同一个线程中执行以下操作:

  • 在你的 ThreadLocal 中设置 UserObj
  • 执行搜索操作并在您的 ThreadLocal 中获取 UserObj

如果你希望我能给你一个示例代码,请告诉我。

于 2013-01-23T02:55:24.177 回答