简体   繁体   English

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

[英]What's wrong with the following getInstance() method

I've been studying for a job interview and I've found this question: 我一直在学习求职面试,但发现了以下问题:

What's wrong with the following Singleton factory method getInstance()? 以下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
    }   
}

I know the constructor is wrong and should be private. 我知道构造函数是错误的,应该是私有的。 However, they're asking about what's wrong with the getInstance() method, everything looks fine to me, I've seen a lot of examples like this one (in a multithreading environement) what am I missing? 但是,他们在问getInstance()方法有什么问题,对我来说一切都很好,我已经看到了很多这样的示例(在多线程环境中),我还缺少什么?

The largest problem with the original code is that it is a classic example of the Double Check anti-pattern. 原始代码的最大问题是,它是Double Check反模式的经典示例。 It looks great but is just broken. 看起来不错,但刚刚坏了。 More on that here: http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html 此处的更多信息: http : //www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

Note that as of java 1.5 there is a way to finesse it, the synchronized pattern or better static initialization is really the way to go. 请注意,从Java 1.5开始,有一种完善的方法,同步模式或更好的静态初始化才是真正的方法。

-edit (I just noticed this is studying for a job interview. Pulling out "double check" if they show this example would be good. If asked for the details, I would go with complex java memory issues you did not fully understand but accept the fact to avoid double check . Good luck) -edit(我刚刚注意到这是在学习求职面试。如果他们显示此示例,请抽出“仔细检查”会很好。如果要求提供详细信息,我将处理一些您不太了解但可以接受的复杂Java内存问题避免再次检查的事实。祝您好运)

This does appear to be thread-safe, however the code is more complex than it needs to be. 这看起来确实是线程安全的,但是代码比需要的复杂。 Plus the use of a lock, comes with a performance cost. 加上使用锁,会带来性能成本。 It takes time to acquire the lock, and other threads attempting to execute that code are blocked. 获取锁需要花费时间,并且其他试图执行该代码的线程也会被阻塞。

These 2 concerns could be addressed by using a static initializer and removing synchronization from the getInstance method entirely. 这两个问题可以通过使用静态初始化程序并从getInstance方法中完全删除同步来解决。 The JVM will ensure that this statement is executed exactly once. JVM将确保该语句仅执行一次。 The result is significantly simpler code, and slightly more-performant code. 结果是大大简化了代码,而使性能略有提高。

public class Singleton {

    private static Singleton mySingleton = new Singleton();

    private Singleton() {}

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

what am I missing? 我想念什么?

Possible memory effects described in JLS 17 , so there is no happens-before relationship between write and read to mySingleton. JLS 17中描述了可能的内存影响,因此对mySingleton的写入和读取之间没有任何先发生后关系。 It is counterintuitive, but if you checked that mySingleton is not null, you can see wrong object. 这是违反直觉的,但是如果您检查mySingleton不为null,则会看到错误的对象。 Ie mySingleton in this example can be written and read at the same time, it is called data-race. 即在此示例中,mySingleton可以同时读写,这称为数据争用。 To fix this program you can just add volatile. 要修复此程序,您只需添加volatile。 According specifications it creates happens-before relationship between write and read. 根据规范,它在写入和读取之间创建事前关联。

Isn't what you have a bit too redundant? 你不是有点多余吗? How about this instead? 怎么样呢?

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

        return mySingleton;
    }

or... 要么...

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

compliments to Mr. Polywhirl 赞扬Polywhirl先生

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM