【问题标题】:When to use proper version of singleton thread-safe implementation?何时使用正确版本的单例线程安全实现?
【发布时间】:2015-08-10 21:29:27
【问题描述】:

我有一个类似无状态助手的类,我想把它做成一个单例。此类将在不同线程之间共享。

我是否正确,在这种情况下(实例不需要巨大的内存分配大小,因此可以在没有资源和性能影响的情况下多次加载)没有必要使用适当的多线程延迟初始化策略来实现这样的单例( Double Checked Locking & volatile, On Demand Holder idiom, Enum Singleton, Synchronized Accessor)?

使用简单的非多线程惰性初始化版本策略(如下面的代码)来实现这样的单例以减少样板代码的数量是否正确?

public class Singleton {
    private static Singleton INSTANCE;

    private Singleton() {
    }

    public static Singleton getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new Singleton();
        }
        return INSTANCE;
    }
}

只有当单例类的状态在不同线程之间共享时,才需要添加适当的多线程版本的单例初始化?

【问题讨论】:

  • 至少将构造函数设为私有!就您的问题而言,它实际上取决于“您的物品有多贵?”。在良好的多线程环境中使用上述代码会导致创建许多实例。
  • 懒惰的开发者模式(我也是)。有小代码模板; enum 不会开箱即用。您可能还会想到容器管理的持久性,例如 OSGi(=面向服务)或者如果您有多个单例的话。
  • 您可以删除整个惰性初始化并将static final 初始化放入类中,该实例将在任何代码能够调用它之前可用 - 它在类加载器运行期间初始化并将除非您使用动态加载并且在超过 1 个地方加载/卸载它,否则永远不会运行两次
  • 谢谢,只是忘记添加私有构造函数了。
  • 我不明白您为什么不想使用按需持有人。这个来自 wiki 的例子,如果你省略 cmets,比你的方法短 1 行,而且我认为更好。 en.wikipedia.org/wiki/…

标签: java multithreading design-patterns concurrency singleton


【解决方案1】:

回答您的问题...不,这是不正确的。

你说它可以加载几次,但在那种情况下它就不是单例了。单例的定义特征是只能有一个实例。

如果可以有多个,那为什么要让它成为一个单例呢?

如果只是无状态的 util 方法,那为什么不直接做静态呢?

【讨论】:

  • 静态方法不方便在单元测试中使用(仅在使用 PowerMock 的情况下),并且不能通过 OOP 方法进行扩展。
  • JMockit 也支持静态调用
  • @Anton - 同意。这是一天结束时的判断电话。如果它只是一小组不涉及服务或任何东西的无状态实用程序方法,那么您可能无论如何都不想模拟它们。如果他们做了更重量级的事情,或者需要嘲笑,那么他们应该是一个真正的单身人士,其中包括所有这些。虽然根据我的经验,嘲笑单身人士也不是很有趣。
【解决方案2】:

如果你的类是完全无状态的 - 让它成为一个只有静态函数的 util 类。

如果您有状态并且想要一个半单例,我会说您所做的事情具有误导性,因为读者无法知道您是否知道您可以获取多个实例这一事实。如果您决定坚持使用您发布的代码 - 将其重命名为 multiton 或仔细记录行为。但是不要仅仅为了减少样板而这样做——事实上,你给读者带来的问题比你要消除的要多。

在我看来,“Initialization on Demand Holder”成语是最好的单例模式。但我一般建议不要使用单身人士。最好在启动线程时将共享实例的引用传递给线程。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-12
    • 2011-01-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多