简体   繁体   中英

Double checked locking without using volatile-keyword and without synchronizing the entire getInstance() method

Following is my singleton class where I am using double-checked-locking without using volatile keyword and without synchronizing the entire getInstance() method:

public class MySingleton {

    private static MySingleton mySingleton;

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

        return mySingleton;
    }
}

According to me, this is thread-safe. If anyone thinks, this is not thread-safe, can someone please elaborate on why he/she thinks this is not thread-safe? Thanks.

Here we have a synchronized write and a non-synchronized read. We don't have any guarantee that the read will get the value set by the write. So this code is buggy. But it's a very subtle bug, especially in multi core CPUs.

If you need to go ahead with the above code for some reason, one solution is to declare the variable as volatile like so:

private static volatile MySingleton mySingleton;

Or else make the read of the variable synchronized . Either of them would solve your issue at the cost of performance.

Another important point is that your temp variable has no use here. It's just a redundant code and does nothing. Instead directly assign it to your mySingleton variable like so,

mySingleton = new MySingleton();

All of the above problems can be solved very easily by using the enum type to make singletons. Since enums are inherently Serializable , we don't need to implement it with a Serializable interface. The reflection problem is also not there. Therefore, it is 100% guaranteed that only one instance of the Singleton is present within a JVM. Thus, this method is recommended as the best method of making singletons in Java.

I wasn't aware of this issue until I read all the comments. The problem is that the various optimization processes (compiler, Hot Spot, whatever) rewrite the code. Your "temp" solution could easily be removed. I find it hard to believe that a constructor could return a partial object, but if knowledgeable contributors are saying so, I'd trust their opinion.

Yes, but I am using a "temp" variable. Doesn't it solve the "partially-created-object" issue?

No. It does not.

Suppose some thread A calls getInstance() , and ends up creating a new instance and assigning the mySingleton variable. Then thread T comes along, calls getInstance() and sees that mySingleton is not null .

At this point, thread T has not used any synchronization. Without synchronization, the Java Language Specification (JLS) does not require that thread T see the assignments made by thread A in the same order that thread A made them.

Let's suppose that the singleton object has some member variables. Thread A obviously must have initialized those variables before it stored the reference into mySingleton . But the JLS allows thread T to see mySingleton != null and yet still see the member variables in their uninitialized state. On some multi-core platforms, it can actually happen that way.

Assigning the object reference to a local temp variable first doesn't change anything. In fact, as Steve11235 pointed out, the temp variable might not even actually exist in the byte codes or in the native instructions because either the Java compiler or the hot-spot compiler could completely optimize it away.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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