Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 具有volatile变量的惰性初始化单例类_Java_Design Patterns - Fatal编程技术网

Java 具有volatile变量的惰性初始化单例类

Java 具有volatile变量的惰性初始化单例类,java,design-patterns,Java,Design Patterns,我遇到了一个单例类{lazy initialization}。代码如下 // Singleton reference for this class private static volatile FileProperties INSTANCE = null; public static FileProperties getInstance() { if (INSTANCE == null) { synchronized

我遇到了一个单例类{lazy initialization}。代码如下

// Singleton reference for this class
    private static volatile FileProperties INSTANCE = null; 

    public static FileProperties getInstance() {
            if (INSTANCE == null) {
                synchronized (FileProperties.class) {
                    if (INSTANCE == null) {
                        INSTANCE = new FileProperties();
                    }
                }
            }
            return INSTANCE;
        }
我的问题是,通过将实例设置为volatile 因为我们已经通过synchronized解决了线程安全问题。
在这种情况下volatile有什么好处吗?

这是因为不使用volatile的双重检查锁定在Java中不是线程安全的

使线程安全的lazy init singleton最简单的方法是创建类持有者,如下所示:

public class SomeClass {
    private static class SomeClassHolder {
        public static final SomeClass INSTANCE = new SomeClass();
    }

    public static SomeClass getInstance() {
       return SomeClassHolder.INSTANCE;
    } 

    private SomeClass() {}

}
由于JVM的行为,这部分代码将在第一次使用
getInstance()
(而不是在类加载器加载SomeClass时)加载SomeClassHolder并创建SomeClass的实例


您根本不需要使用任何同步!!因为JVM正在为您执行此操作。

查看此双重检查锁定有一个潜在错误,即在FileProperties的构造函数完全执行之前,可能会为实例变量分配一个非空值。当然,如果构造函数是空的,这并不重要。@ JakobJenkov可能是值得澄清的:如果实例不易挥发。考虑添加私有的编译器也可以用于代码。双重检查锁定自从引入java“Value(Java 1.5)的“发生在前面”的含义之前就已经是线程安全的。此外,您还缺少一个私有构造函数。从Java1.5开始,只要您还使用
volatile
,Java中的CL是线程安全的。(我自己不会使用它,但它是线程安全的。)@Bohemian:
volatile
我相信是从1.0开始使用Java的。正确实现的DCL自1.5中更改内存模型以来一直是线程安全的。谢谢各位,但不是没有关键字
volatile
,这就是答案所在。@JonSkeet Yep,你说得对。从1.5开始,强制执行“之前发生”。干杯