在以单例模式创建对象时,引用返回什么

时间:2017-09-15 07:38:22

标签: java

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

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;

3 个答案:

答案 0 :(得分:1)

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

test = new Test()有可能首先创建对象,然后将对它的引用分配给test,然后才初始化它。

因此线程B将引用object,但它可能未初始化。

答案 1 :(得分:0)

这个似乎也是 Bill Pugh 建议的一个好方法,以消除双重检查锁定的缺点(如问题所述)我们不知道我需要进行急切的初始化以消除这种情况:

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类实例。

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

答案 2 :(得分:0)

  

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

确实,这个:

private Test test;

应该声明:

private volatile Test test;

否则线程B 的内存可能保持test的陈旧版本可能null A使用私有构造函数对其进行评估。

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

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

作为两个很好的选择,你可以使用enum singleton idiom:

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

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

或者Bill Pugh单身成语(这里有热切的味道):

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