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?
singleton
from within a synchronized block, and the first thread also writes from the same block. At that point,singleton
must be visible to any reading thread. The fact that it is also later accessed outside the block doesn't seem to matter to me, it's already guaranteed visible at that point. – Snooker