【问题标题】:Is this singleton implementation correct?这个单例实现是否正确?
【发布时间】:2019-11-26 09:55:33
【问题描述】:

由于双重锁检查在优化的编译器上不起作用,我将其从我的单例类中删除,而不是进行早期初始化。

下面是我的新单例类:

class MySingleton {
    private static volatile MySingleton myInstance = new MySingleton();
    public static getInstance() {
        return myInstance;
    }
}

除了getInstance(),类中还有设置成员字段值的setter方法。

希望当多个线程使用同一个对象更新各个成员字段时,此实现不会导致任何数据不一致。

欢迎提出任何建议或意见。

【问题讨论】:

  • @HadiJ 我完全同意我需要定义一个私有构造函数。但我想这将是线程安全的,并且不需要同步,因为静态字段将在类加载期间创建。由于我的引用是静态的,因此任何尝试访问的线程都可以使用它。

标签: multithreading design-patterns java-8 singleton


【解决方案1】:

此代码是线程安全的。事实上,您可以删除volatile,它仍然是线程安全的。

myInstance 变量在第一个 getInstance 调用触发静态初始化(如果尚未发生)时被初始化。初始化和第一次调用有一个happens-before

不过,你也这么说:

希望当多个线程使用同一个对象更新各个成员字段时,此实现不会导致任何数据不一致。

您还没有展示任何用于执行此操作的代码,因此我们无法告诉您代码是否是线程安全的。如果MySingleton 实例是可变的,那么与状态相关的方法必须适当地同步以防止内存危害和竞争条件。您向我们展示的代码并未解决此问题。


因为默认的MySingleton 构造函数是public,所以这不是一个合适的单例类。可以创建多个实例。


此实现与许多其他实现的不同之处在于,杰出的MySingleton 实例是急切地创建而不是懒惰地创建的。这大大简化了问题。

请注意,单例的延迟初始化通常是不必要的。如果您不是特别需要延迟初始化,那么更简单的 Eager 替代方案就可以了。

【讨论】:

  • 正如您所说,实例是在第一次 getInstance 调用上创建的,这几乎是“急切地创建的”。以不同方式进行的“许多实现”通常试图解决一个不存在的问题。无论如何,媒体中的外观与单例模式在现实生活中的实际相关性之间存在不匹配。
  • 并且必须强调的是,单例的实现对问题中提到的OP的setter方法所做的更新的安全性没有影响。
  • 合并。谢谢。
【解决方案2】:

您的单例是线程安全的,但除了调用 getInstance() 之外,还有其他事情可能导致初始化 MySingleton 类,从而构造实例。

解决这个问题的常用方法是将单例放入私有嵌套类中,如下所示:

class MySingleton {
    private MySingleton() {
        // there can only be one
    }
    private static class Holder {
        static final MySingleton instance = new MySingleton();
    }
    public static MySingleton getInstance() {
        return Holder.instance;
    }
}

现在实例只能在 Holder 类初始化时构建,并且只在第一次调用 getInstance() 时发生

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-21
    • 1970-01-01
    • 2013-08-15
    • 1970-01-01
    相关资源
    最近更新 更多