参考在单元模式中创建对象时会返回什么



以下是单例模式的双检查实现。线程A正在执行test=new Test();线路,但同时,线程B首先检查test的值。 test的值是什么?

class Test {
    private Test test;
    private Test() {        
    }   
    public static Test get() {
        if (test == null) {    // Thread B. When object is being created, 
                               // what's value of test. Is it always null before 
                               // Thread B new object?
            synchronized (test.getClass()) {
                if (test == null) {
                    test = new Test(); // Thread A. This thread is creating object.
                }
            }
        }
        return test;
    }
}

添加
如果它不是单身模式的正确版本,volatile关键字可以解决问题吗?也就是说,private volatile Test test;

它是未知的。这就是为什么此实现被认为是错误的。

test = new Test()首先创建对象,然后将其分配给test,然后初始化。

因此,线程B会引用对象,但可能不会初始化。

这似乎也是一种很好的方法在问题中),我们也不需要急切的初始化来消除这一点:

public class BillPughSingleton {
   private BillPughSingleton(){}
   private static class SingletonHelper{
     private static final BillPughSingleton INSTANCE = new BillPughSingleton();
   }
   public static BillPughSingleton getInstance(){
    return SingletonHelper.INSTANCE;
   }
}

请注意包含Singleton类实例的private inner static class。加载单例类时,SingletonHelper class不会加载到内存中,并且仅当有人调用getInstance方法时,此类将加载并创建Singleton类实例。

这是单身类别类最广泛使用的方法之一,因为它不需要同步。

如果它不是单例模式的正确版本,则可以挥发关键字 解决问题?

的确,这个:

private Test test;

应声明:

private volatile Test test;

否则,线程的内存B May 保留 May test的陈旧版本是null,而线程A用私有构造函数对其进行了评估。


<<br> <<br> <<br> <<br> <<br> <<br> <<br> <<br> <<br> <<br>













/p>

通过将test指定为volatile,您可以确保其他线程可以看到一个线程执行的任何分配。


现在,这种实现单例的方式不是很直(双条件语句加显式同步)。

作为两个很好的替代方案,您可以使用Enum Singleton Idiom:

public enum Test implements TestInterface{
   SINGLETON;
   ...
}

请注意,建议接口编写自然测试的实现并能够切换到其他实现。

否则Bill Pugh Singleton Idiom(这里是渴望的风味):

public class Test{
    // executed as soon as the T class is loaded by the classLoader
    private static Test instance = new Test();
    private Test() {
    }
    public static TestgetInstance() {
      return instance;
    }
}

最新更新