以下getInstance()方法有什么问题

时间:2014-11-10 02:49:33

标签: java concurrency singleton

我一直在求职面试,我发现了这个问题:

以下Singleton工厂方法getInstance()?

有什么问题
public class Singleton {

    private static Singleton mySingleton;

    protected Singleton() {}

    public static Singleton getInstance() {
        if (mySingleton == null) {
           synchronized(Singleton.class) {
             if(mySingleton == null) {
                mySingleton = new Singleton();
             }
           }
        }
        return mySingleton
    }   
}

我知道构造函数是错误的,应该是私有的。然而,他们一直在询问getInstance()方法有什么问题,一切看起来都不错,我已经看过很多像这样的例子(在多线程环境中)我是什么丢失?

4 个答案:

答案 0 :(得分:4)

原始代码的最大问题在于它是 Double Check 反模式的典型示例。它看起来很棒,但只是破碎了。更多内容如下: http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

请注意,从java 1.5开始,有一种方法可以使用它,同步模式或更好的静态初始化是真正的方法。

-edit (我刚刚注意到这是为了求职面试。拔出"仔细检查"如果他们展示这个例子会很好。如果被问到详细信息,我会选择你没有完全复杂的java内存问题理解,但接受事实,以避免仔细检查。祝你好运)

答案 1 :(得分:1)

这似乎是线程安全的,但代码比它需要的更复杂。另外,使用锁具还有性能成本。获取锁需要一些时间,并且试图执行该代码的其他线程被阻止。

这两个问题可以通过使用静态初始化程序并完全从getInstance方法中删除同步来解决。 JVM将确保此语句只执行一次。结果是代码明显更简单,代码性能稍高一些。

public class Singleton {

    private static Singleton mySingleton = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() {
        return mySingleton;
    }   
}

答案 2 :(得分:0)

  

我错过了什么?

JLS 17中描述的可能的记忆效应,因此写入和读取mySingleton之间没有发生过关系。这是违反直觉的,但如果您检查mySingleton不为null,则可以看到错误的对象。即在这个例子中mySingleton可以同时写入和读取,它被称为数据竞争。要修复此程序,您只需添加volatile即可。根据规范,它创建发生在写和读之间的关系之前。

答案 3 :(得分:-1)

难道你有点过于冗余吗?怎么样呢?

public static synchronized Singleton getInstance()
    {
        if (mySingleton == null)
            mySingleton = new Singleton();

        return mySingleton;
    }

...或

public static synchronized Singleton getInstance()
    {
        return mySingleton==null?mySingleton=new Singleton():mySingleton;
    }

赞扬Polywhirl先生