你应该为单例模式使用 AtomicReference 吗?

Should you use the AtomicReference for the Singleton Pattern?

我 运行 跨越 AtomicReference class 并且想知道这是否是创建可变且可以替换以进行测试的单例的好方法。

我知道双锁检查有问题所以我不想走那条路。 从 JDK 1.5 开始更正, https://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html.
另外,我更愿意懒惰地实例化单例而不是初始化它。例如,在测试期间,我不想使用默认值 class SimpleExample,但在某些情况下,它要么创建成本高昂,要么在某些环境中存在问题。我希望能够在请求之前更换它。

public class SingletonExample {

  private static AtomicReference<SingletonExample> sInstance = new AtomicReference<>();

  private SingletonExample() {
  }

  public static SingletonExample getInstance() {
      return sInstance.updateAndGet(u -> u != null ? u : new SingletonExample());
  }

  @VisibleForTesting
  static void setInstance(SingletonExample singletonExample) {
      sInstance.set(singletonExample);
  }
}

这是我的问题:

  1. 性能受到很大影响吗?
  2. 是否存在我不知道将其用作单例的问题?
  3. 什么是合理的替代方案?
  1. Is there a big performance hit?

与任何事情一样:视情况而定。

"With low to moderate contention, atomics offer better scalability; with high contention, locks offer better contention avoidance."

来自 Goetz 第 15.3.2 节的 "Java Concurrency In Practice"

  1. Is there an issue that I am not aware of using it as a Singleton?

因为您没有使用锁定,所以参数 lamda 看起来可能 运行 同时被多个线程使用。因此,您可以创建和设置多个 SingletonExample 对象,但每个线程都会看到每个更新:

public static SingletonExample getInstance() {
  return sInstance.updateAndGet(u -> u != null ? u : new SingletonExample());
}
  1. What are reasonable alternatives?

我会坚持简单锁定,因为:

  1. 它如您所愿。所以你只创建了一次 SingletonExample。
  2. 允许您将状态变量组合在一起,这是 volatileAtomicReferences 无法做到的。