这个单例实现正确吗?

时间:2019-11-26 09:55:33

标签: multithreading design-patterns java-8 singleton

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

下面是我的新单身人士课:

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

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

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

欢迎任何建议或投入。

2 个答案:

答案 0 :(得分:3)

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

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

但是,您也这样说:

  

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

您尚未显示用于执行此操作的任何代码,因此我们无法告诉您那个代码是否是线程安全的。如果MySingleton实例是可变的,则状态相关的方法必须适当地同步,以防止出现内存危险和争用条件。您显示给我们的代码无法解决此问题。


由于默认的MySingleton构造函数是public,因此这不是适当的单例类。可以创建多个实例。


此实现与许多其他实现的不同之处在于,抢先而非延迟地创建了独特的MySingleton实例。这大大简化了问题。

请注意,单例的惰性初始化通常是不必要的。如果您不需要专门的延迟初始化,那么更简单的替代方法就可以了。

答案 1 :(得分:0)

您的单例是线程安全的,但是除了调用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()

时才可以构造该实例。