Threadsafe Singleton without synchronization in Java?
Asked Answered
A

1

7

I have a multithreaded application and a singleton class:

public final class Singleton {

    private static MyClass mc;

    public static final Object getInstance() {
            if(mc == null) {
                mc = new MyClass();
            }
            return mc;
    }

}

Of course, this will not work in a general multithreaded scenario. But consider the following scenario:

  • In the beginning there is only one thread
  • This one thread calls getInstance() for the first time so that mc is initialized.
  • After that all other threads are started by the first thread.

My assumption:

This should work because the initialization of the mc field and the object's construction happen-before all subsequent Thread.start() calls that start the other threads. And the Thread.start() for a thread happens-before all other actions of that thread. It follows that the initialization of mc happens-before all actions in all other threads so that getInstance() will return the right value for all threads.

Is this assumption right? Why / Why not?

Airport answered 6/11, 2014 at 21:49 Comment(9)
Well, @StephenC, or I SHOULD ask people who (hopefully) understand the JMM and thus can EXPLAIN it to me.Airport
It'll be fine. It's called "eager initialization" (well essentially, although your form is a bit different, that is ultimately what you are doing). Google it. See also journaldev.com/1377/…Philippe
Yes it works but it is very fragile as you can imagine. And the cost of making it right, performance wise, is negligible.Trophy
@Trophy So the assumption is right? What exactly makes it that fragile?Airport
The thread safety depends on the caller respecting your workflow as opposed to being guaranteed by the design of the class.Trophy
You could simply use final MyClass singleton = new MyClass(); it's eager and perfectly threadsafe - en.wikipedia.org/wiki/Singleton_pattern#Eager_initialization - lazy initialization has only benefits if there are chances that this class is just partially required long before you'll need the instance. In most cases, class loading (=static initialization) is the exact same time you need the singleton.King
@Trophy I know that the class itself is not threadsafe. But in the described scenario? Does the memory model predict this as working or not? (And please post it as an answer so that I can accept it and you get reputation :D )Airport
@King I know and I won't use this fragile solution but it's about understanding the JMM and what it allows and disallows.Airport
Since you've tagged that: The "Double-Checked Locking is Broken" Declaration - that's a) a good example for horrible things that can happen multithreaded b) written with the old memory model in mind. Some parts are no longer correct and you can in fact use double checked locking in a very specific way that is explained in the end. Also jeremymanson.blogspot.de/2008/05/double-checked-locking.html is a good (up to date) read. And if you're still not satisfied read JCIPKing
C
5

Your analysis is indeed perfectly fine.

To be precise: Everything that happens on one thread sequentially has a happens before relationship (obviously, the says it this way: "If x and y are actions of the same thread and x comes before y in program order, then hb(x, y)." )

17.4.5 of the JLS then goes on to say the following:

"A call to start() on a thread happens-before any actions in the started thread."

So taken together there's a clear happens before order between the singleton instantiation and the started threads, hence they're guaranteed to see the up to date value.

Simply said: A created thread is guaranteed to see everything its parent did before it was created, otherwise concurrent programming would be nigh impossible.

Culture answered 6/11, 2014 at 22:53 Comment(3)
I can confirm that @Culture is 100% correct. I've been doing just that for over a decade now with no problems.Lelialelith
@StephenC The reasoning is based on the rules of the JMM about happens before relations and when they exist between two actions. What would be the better reasoning in your opinion?Airport
@Stephen The given explanation by the OP seems pretty close to what I have, dieting that you can establish a hb sequence between the actions. Which yes, seems perfectly fine to me.Culture

© 2022 - 2024 — McMap. All rights reserved.