2017-09-15 54 views
0

以下是仔细检查单例模式的实现。线程A正在执行行test=new Test();但是就在同一时间,线程B首先检查值test。对于线程B,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;

+0

这必须是静态的...:***公开测试的get(){***若不是没有因为你将需要一个Test类的实例,以便能够调用get方法 –

+0

@ΦXocę웃Пepeúpaツ对不起,我对它进行了修改。 – user7328234

回答

1

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

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

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

+1

此链接https://www.javaworld.com/article/2074979/java-concurrency/double-checked-locking-clever--but-broken.html可以很好地解释它。 它可以避免使用资源的预先初始化。这种方法并不是一如既往,但会在这种特殊情况下消除这个问题。 – Punit

0

这其中也似乎是一个很好的方法,通过比尔普格的建议,以消除双重检查锁定(如问题提到的)的缺点,我们也不需要做初始化的渴望,以及对消除此:

public class BillPughSingleton { 

    private BillPughSingleton(){} 

    private static class SingletonHelper{ 
    private static final BillPughSingleton INSTANCE = new BillPughSingleton(); 
    } 

    public static BillPughSingleton getInstance(){ 
    return SingletonHelper.INSTANCE; 
    } 
} 

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

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

0

如果不是单件模式的正确版本,可以通过volatile关键字 来解决问题吗?

事实上,这样的:

private Test test; 

应该声明:

private volatile Test test; 

否则线程的内存B可以保持test一个陈旧的版本,可能null而线程A重视与私人构造函数。

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


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

由于两位漂亮的替代品,你可以使用枚举单成语:

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

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

否则比尔普格单成语(这里是在急于味):

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; 
    } 
} 
相关问题