Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In a Thread Safe Singleton does the return have to be inside the synchronized block

Consider the following code:

private static Singleton singleton;

public static Singleton get(){
    synchronized (Singleton.class) {  
        if (singleton == null) {  
            singleton = new Singleton();  
        }  
    } 
    return singleton; // <-- this part is important
}

This comes as a follow-up discussion from this question. Initially, I thought that it was thread-safe. However, some respectable users argue that is not thread-safe because of the return singleton outside the synchronized block. Some other also (respectable) users, however, argued otherwise.

After I have read do we need volatile when implementing singleton using double-check locking, I changed my mind. (The code from that question):

    private static Singleton instance;

    private static Object lock = new Object();

    public static Singleton getInstance() {
        if(instance == null) {
            synchronized (lock) {
                if(instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }

(It is well-known why the volatile is needed on the second code.)

However, after looking again at both examples, I have noticed that there is a big difference between the first and the second code snippets. On the former the outermost if is inside the synchronized clause therefore all the threads running within the synchronized block will force a happen-before relation (i.e., there is no way threads will return null if the instance was properly set) Or am I wrong? I would expect the following order of actions:

lock monitor
...
unlock monitor
...
read singleton

I have noticed that all the examples online that are similar to the first code snippet have the return inside the synchronized block; However, that can be simply because performance-wise it is the same since threads have to synchronized away, so why not be on the safe side and put the return inside?!.

Question:

Does the return really need to be inside the synchronized block? Can the read of the singleton value for the return statement see a value of the singleton before the synchronized block start?

like image 826
dreamcrash Avatar asked Mar 16 '21 21:03

dreamcrash


People also ask

Can a singleton be thread-safe?

Is singleton thread safe? A singleton class itself is not thread safe. Multiple threads can access the singleton same time and create multiple objects, violating the singleton concept. The singleton may also return a reference to a partially initialized object.

What is Singleton design pattern How will you make it thread-safe?

Thread Safe Singleton: A thread safe singleton is created so that singleton property is maintained even in multithreaded environment. To make a singleton class thread safe, getInstance() method is made synchronized so that multiple threads can't access it simultaneously.

Is double locking must to create thread-safe singleton class?

In double-checked locking, code checks for an existing instance of Singleton class twice with and without locking to make sure that only one instance of singleton gets created. Need of Double-checked Locking of Singleton Class: Java.

Is thread-safe means synchronized?

To make it thread safe then, you have to force person 1 to wait for person 2 to complete their task before allowing person 1 to edit the document. Synchronized means that in a multiple threaded environment, a Synchronized object does not let two threads access a method/block of code at the same time.

How to implement a thread safe singleton class in Java?

2 Ways to implement a thread safe singleton class in java 5.1 Using static inner class 5.2 Using static initializer block The important concept behind the singleton design pattern is to have no more than one instance of the target class at any given time per java virtual machine.

Is Meyers Singleton thread safe C++?

Meyers Singleton. The beauty of the Meyers Singleton in C++11 is that it's automatically thread-safe. That is guaranteed by the standard: Static variables with block scope. The Meyers Singleton is a static variable with block scope, so we are done. It's still left to rewrite the program for four threads.

Can Singleton be used in a single threaded environment?

It can be used in a single threaded environment because multiple threads can break singleton property because they can access get instance method simultaneously and create multiple objects. Object is created only if it is needed. It may overcome resource overcome and wastage of CPU time.

How to make getInstance() method thread safe?

The most naive thread-safe solution is to make whole getInstance () method as synchronized. Synchronized keyword makes a method thread safe, but with extra overhead. Note: it will take a lock on complete class (static method) unnecessary, which is a costly operation.


1 Answers

Does the return really needs to be inside the synchronized block?

No the return does not need to be in the synchronized block unless the singleton field can be assigned elsewhere. However, there is no good reason why the return shouldn't be inside of the synchronized block. If the entire method is wrapped in a synchronized then you can just mark the method as synchronized if we are in the Singleton class here. This would be cleaner and better in case singleton gets modified elsewhere.

In terms of why it doesn't need to be inside, since you are using a synchronized block, there is a read-barrier crossed at the start of the block and a write-barrier at the end, meaning that the threads will get the most up-to-date value of singleton and it will only be assigned once.

The read memory barrier ensures that the threads will see an updated singleton which will either be null or a fully published object. The write memory barrier ensures that any updates to singleton will be written to main memory which includes the full construction of Singleton and the publishing of it to the singleton field. Program order guarantees that the singleton assigned within the synchronized block will be returned as the same value unless there is another assignment in another thread to singleton then it will be undefined.

Program order would be more in force if you did something like the following. I tend to do this when singleton is volatile (with appropriate double-check locking code).

synchronized (Singleton.class) {
    Singleton value = singleton;
    if (singleton == null) {
       value = new Singleton();
       singleton = value;
    }
    return value;
}

not thread-safe because of the return singleton outside the synchronized block

Since you are using a synchronized block, this isn't an issue. The double check locking is all about trying to avoid the synchronized block being hit on every operation as you point out.

all the threads running within the synchronized block will force a happen-before relation (i.e., there is no way threads will return null if the instance was properly set) Or am I wrong?

That's correct. You aren't wrong.

However, that can be simply because performance-wise it is the same since threads have to synchronized away, so why not be on the safe side and put the return inside?!.

No reason not to although I would argue that the "safe side" is more about causing consternation when others review this code and are worrying about it in the future, as opposed to being "safer" from the standpoint of the language definition. Again, if there are other places where singleton is assigned then the return should be inside of the synchronized block.

like image 152
Gray Avatar answered Oct 22 '22 06:10

Gray