Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is this static final variable in a singleton thread-safe?

Reading this site, I've found this:

[The] line private static final Foo INSTANCE = new Foo(); is only executed when the class is actually used, this takes care of the lazy instantiation, and is it guaranteed to be thread safe.

Why this guaranteed to be thread safe? Because this field is final? Or for some other reason?

like image 559
WelcomeTo Avatar asked Jan 14 '12 20:01

WelcomeTo


4 Answers

Because it's final, yes. Final variables have special thread-safety semantics, in that other threads are guaranteed to see the final field in at least the state it was in when its constructor finished.

This is in JLS 17.5, though the language there is a bit dense. These semantics were introduced in Java 1.5, in particular by JSR-133. See this page for a non-spec discussion of JSR-133 and its various implications.

Note that if you modify the instance after its constructor, that is not necessarily thread safe. In that case, you have to take the usual thread safety precautions to ensure happens-before edges.

I'm fairly sure (though not quite 100%) that the fact that only one thread does the class initialization is not a factor here. It's true that the class is only initialized by one thread, but I don't believe there are any specific happens-before edges established between that thread any any other thread that uses the class (other than that other thread not having to re-initialize the class). So, without the final keyword, another thread would be able to see a partially-constructed instance of the object. The specific happens-before edges the JMM defines are in JLS 17.4.5, and class initialization is not listed there.

like image 133
yshavit Avatar answered Oct 22 '22 11:10

yshavit


Class constructors and static/instance initializers are guaranteed to be atomically executed and since private static final FOO INSTANCE = new FOO; is equivalent to

private static final FOO INSTANCE;

static{
    INSTANCE = new FOO();
}

this case falls in the above category.

like image 33
asenovm Avatar answered Oct 22 '22 10:10

asenovm


It is guaranteed to be thread safe because the JVM guarantees that static initializers are executed on a single thread.

It doesn't mean that the instance of Foo is internally thread safe- it just means that you are guaranteed that the constructor of Foo will be called exactly once, on one thread, via this particular code path.

like image 36
Chris Shain Avatar answered Oct 22 '22 11:10

Chris Shain


The static initialisation block of any class is guaranteed to be single threaded. A simpler singleton is to use an enum

enum Singleton {
    INSTANCE;
}

This is also threads safe and the class lazy-initialised.

like image 2
Peter Lawrey Avatar answered Oct 22 '22 12:10

Peter Lawrey