15

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?

Community
  • 1
  • 1
WelcomeTo
  • 19,843
  • 53
  • 170
  • 286

4 Answers4

26

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.

Laurel
  • 5,965
  • 14
  • 31
  • 57
yshavit
  • 42,327
  • 7
  • 87
  • 124
  • I believe the more important reason than final is that the class initialization (static initialization) must be synchronized and thread safe. It using synchronization does establish the happens-before ordering. See 12.4.2 ( http://java.sun.com/docs/books/jls/third_edition/html/execution.html#12.4.2) for more detail. – sjlee Jan 16 '12 at 01:49
  • @sjlee It's true that initialization requires locks, but if thread A initializes MyClass, and thread B comes around 5 minutes later and uses MyClass, thread B won't try to initialize MyClass (because it's already been initialized). That means it won't obtain the lock on `MyClass.class`, which means there's no happens-before relationship between thread A's actions and thread B's. If every thread did lock on `MyThread.class` whenever it used it, you'd never need to establish any other happens-before relationships. – yshavit Jan 16 '12 at 03:01
5

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.

asenovm
  • 6,397
  • 2
  • 41
  • 52
3

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.

Chris Shain
  • 50,833
  • 6
  • 93
  • 125
2

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.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • Reference for this, e.g. JLS? – calebds Jan 14 '12 at 20:26
  • @paislee: I'm more at home in the JVMS so I can provide you with a [reference to that](http://java.sun.com/docs/books/jvms/second_edition/html/Concepts.doc.html#24237). If you follow the procedure you see that class initialization may only be done by a single thread (per classloader). The static initializer is called in step 8. – musiKk Jan 14 '12 at 20:33
  • 1
    The JVMS provides stricter semantics than the JLS in various ways, so it's not a great source for general language correctness. The JLS defines class initialization in [JLS 12.4](http://java.sun.com/docs/books/jls/third_edition/html/execution.html#12.4), and 12.4.2 details the procedure specifically. – yshavit Jan 14 '12 at 20:44