2013-05-14 56 views
2

我遇到了一个单例类{lazy initialization}。代码如下懒惰初始化具有volatile变量的Singleton类

// 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; 
     } 

我的问题是什么是我们正在通过使实例作为挥发性 既然我们已经照顾线程安全的通过同步获取利益。 在这种情况下是否有挥发性的好处?

+1

请参阅http://jeremymanson.blogspot.co.uk/2008/05/double-checked-locking.html – 2013-05-14 11:51:59

+1

这种双重检查的锁定有一个潜在的错误,因为INSTANCE变量可能被赋予一个非空值*之前* FileProperties的构造函数已完全执行。当然,如果构造函数是空的,这并不重要。 – 2013-05-14 11:55:14

+1

@JakobJenkov也许值得澄清:** IF ** INSTANCE不易变。 – assylias 2013-05-14 11:56:34

回答

5

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

,使线程安全的lazy-init来单最简单的方法是创建类持有人如下:

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

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

    private SomeClass() {} 

} 

的代码部分,因为JVM的行为将加载SomeClassHolder和创建SomeClass的实例第一次使用getInstance()(而不是当SomeClass由类加载器加载时)。

根本不需要使用任何同步!因为JVM正在为你做。

+0

自从volatile引发“发生在......之前”(Java 1.5)以来,双重检查锁定一直是线程安全的。此外,你错过了一个私有的构造函数 – Bohemian 2013-05-14 11:59:48

+1

只要你还*使用'volatile',DCL *就是从Java 1.5开始的Java中的线程安全的。 (我不会自己使用它,但是它是线程安全的。) – 2013-05-14 12:00:01

+0

@ Bohemian:我相信''volatile'在Java中是1.0。由于内存模型在1.5版本中改变,所以正确实施的DCL是线程安全的。 – 2013-05-14 12:00:26