java - 如何创建 session 范围的线程安全对象实例?

标签 java multithreading architecture synchronization

我希望在我的程序中为线程安全的 session 提供一个可重置对象实例, session 的一个示例可能是登录的用户 session 。

我目前正在做这样的事情;

  public final class ObjectFactory {

    private static volatile NativeObjectWrapper instance = null;

    private Singleton() {}

    public static NativeObjectWrapper getInstance() {
        if (instance == null) {
            synchronized(ObjectFactory.class) {
                if (instance == null) {
                    instance = new NativeObjectWrapper(AuthData);
                }
            }
        }

        return instance;
    }

    public void reset() {
      synchronized(ObjectFactory.class) {
        instance = null;
      }
    }
  }

我想要延迟创建对象,能够重置它。上述方法是线程安全的吗?如果没有,是否有通用模式来解决这个问题?

再举一个例子,这里的作用域对象有一些基于用户 session 的内部数据,因此应该是每个用户 session 的一个新实例。

最佳答案

Is the above approach threadsafe?

不,不是。

假设我们有两个线程 - AB

A 调用 getInstance(),通过 instance==null 检查,然后上下文切换到 B,后者调用 reset()B 执行完 reset() 后,A 再次获取上下文并返回 instance,现在该实例为 null。

if not is there a common pattern to solve this?

我不记得见过带有 reset 方法的单例,所以我不知道此问题的任何常见模式。不过,最简单的解决方案是删除 getInstance() 中的第一个 if (instance == null) 检查。这将使您的实现线程安全,因为 instance 始终在同步块(synchronized block)内检查和修改。在这种情况下,您还可以从实例中删除 volatile 修饰符,因为它始终是从同步块(synchronized block)内访问的。

我可以想到更复杂的解决方案,但只有当现实世界的分析表明您在同步 block 上花费了太多时间时,我才会使用它们。请注意,JVM 有 some sophisticated ways避免使用“真正的”锁来最大限度地减少阻塞。

一种更棘手的方法可能是只读取 instance 字段一次:

public static Singleton getInstance() {
    Singleton toReturn = instance;
    if (toReturn == null) {
        synchronized(SingletonFactory.class) {
            if (instance == null) {
                instance = new Singleton();
                toReturn = instance;
            }
        }
    }

    return toReturn ;
}

但这可能会导致返回旧的“实例”。例如,一个线程可以执行 Singleton toReturn = instance 并获得一个有效的实例,然后失去 CPU。此时,1000 个其他线程可以创建并重置 1000 个其他实例,直到原始线程再次在 CPU 上旋转,此时它返回旧的实例值。这种情况是否可以接受取决于您。

关于java - 如何创建 session 范围的线程安全对象实例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58631569/

相关文章:

c# - C# 中是否有与此 Java 代码等效的代码?

java - Java线程坏了

java - 在容器管理的实体管理器中获取 javax.persistence.TransactionRequiredException

java - 检测流是否用 Java 压缩的最佳方法

ios - iPhone - 异步 NSURLConnection HTTP 响应可能会干扰正在运行的进程吗?

java - 哪个类(class)应该做这项工作?

architecture - API 网关和 ACL

ruby-on-rails - Rails - 如何避免不同应用程序之间的重复

java - Android - 使用 ViewGroup 的 NullPointerException

java - Orika 类 com.sun.proxy 无法访问