【问题标题】:Should you use the AtomicReference for the Singleton Pattern?你应该为单例模式使用 AtomicReference 吗?
【发布时间】:2018-03-20 19:58:00
【问题描述】:

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

我知道双锁检查有问题,所以我不想走那条路。 自 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. 什么是合理的替代方案?

【问题讨论】:

  • 什么是合理的替代方案? - 不要使用signleton。
  • 您提供的代码似乎并没有提供很多常规 volatile 字段无法提供的功能。因此,您想对产品和测试使用不同的实现,我想这是可以理解的,但是“在某些环境中创建成本高或有问题”是什么意思?我敢赌甜甜圈,有很多比使用像单例模式这样粗糙的东西更好的方法来做你需要的事情。
  • 另外,mutable 单例是一条通往地狱的道路。等着有人发现他们可以根据自己的需要设置不同的实现。
  • 我更喜欢懒惰地实例化单例而不是初始化它”但是类初始化和你的代码一样懒惰。它只会在第一次调用getInstance() 时发生。当getInstance() 被多次调用时,你只是在浪费资源。

标签: java multithreading design-patterns singleton atomicreference


【解决方案1】:
  1. 性能是否受到很大影响?

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

“在低到中等的争用情况下,原子提供更好的可扩展性;在高争用情况下,锁可以更好地避免争用。”

来自 Goetz 的“Java 并发实践”第 15.3.2 节

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

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

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

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

  1. 它按您的预期工作。因此,您只需创建一次 SingletonExample。
  2. 允许您将状态变量组合在一起,这是 volatileAtomicReferences 无法做到的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-23
    • 2017-06-12
    相关资源
    最近更新 更多