2

我遇到了AtomicReference类,想知道这是否是创建一个可变且可以替换以进行测试的 Singleton 的好方法。

我知道双锁检查有问题,所以我不想走那条路。 自 JDK 1.5 起更正,https://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
此外,我更愿意懒惰地实例化单例而不是初始化它。例如,在测试期间,我不想使用默认类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. 是否存在我不知道将其用作 Singleton 的问题?
  3. 什么是合理的选择?
4

1 回答 1

0
  1. 有很大的性能影响吗?

与任何事情一样:这取决于。

“对于低到中等的争用,原子提供了更好的可扩展性;对于高争用,锁提供了更好的争用避免。”

来自 Goetz 的“Java Concurrency In Practice”第 15.3.2 节

  1. 是否存在我不知道将其用作 Singleton 的问题?

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

public static SingletonExample getInstance() {
  return sInstance.updateAndGet(u -> u != null ? u : new SingletonExample());
}
  1. 什么是合理的选择?

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

  1. 它按您的预期工作。所以你只创建一次 SingletonExample 。
  2. volatile允许您将状态变量组合在一起,而使用or则无法做到这一点AtomicReferences
于 2018-03-21T18:04:34.870 回答