Here is a singleton thread safe:

 public class Singleton { private volatile static Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } } 

I don’t understand why he needs volatile , if it already crashes on Singleton.class . What does it save from?

  • 2
  • one
    @arkadij_ok I know what volatile and even know about the processor cache. The question is, why should we make the instance protected from caching, if the second check occurs inside the locked monitor? - faoxis
  • Did not know that you can synchronize by Object.class - JAVAvladuxa

2 answers 2

The object creation operation in Java is not atomic.

Consider ( one of the possible ) an example with the operation of creating an object and two threads:

Поток A enters the getInstance() method, at this point in time, instance == null and it enters a synchronized block, in which instance == null also starts creating a Singleton object. First, memory is allocated for an object, then this object is initialized with a reference to the allocated memory area. At this point in time, Поток B enters the getInstance() method and sees that instance != null and begins to use an already existing, but not yet ground, constructed object (since its fields have not yet been initialized).

Declaring the instance field as volatile ( JDK 5+ ) sets the happens before relationship between initializing the object of instance Потоком A and returning the object of instance Потоку B

In other words, declaring an instance field as volatile ensures that поток В reads a fully constructed instance object.

UPD. From @Roman comments , another reason for using volatile :

Without volatile there is another problem: if the first if (instance == null) check does not see null , the subsequent return instance can see null , as a result, the method returns null .

If there is no correct synchronization, the reading that goes "later" can see the value that was "earlier", because JMM does not prohibit reordering such readings.

A variable declared volatile is never cached into the memory of the thread, that is, it will have the same ( actual ) value at any time in any thread (if one thread changes its value, then this value is immediately available in other threads).

  • Without volatile there is another problem: if the first if (instance == null) check does not see null , the subsequent return instance can see null , as a result, the method returns null . - Roman
  • @Roman; And how can an instance be reset in this implementation? - post_zeew
  • Nobody clears the instance . Simply, if there is no correct synchronization, the reading that goes "later" can see the value that was "earlier", since JMM does not prohibit reordering such readings. See a simple example and an example from a question (Unsafe DCL + Safe Singleton). - Roman
  • @Roman, Thanks, added in response. - post_zeew

Because reading when comparing

 if (instance == null) { 

happens outside of a synchronized block, and sideeffects can already be, for example, a created object in a heap, but with a not yet called constructor or a cached value of null. The JDK 5.0 and higher memory model requires that the behavior of multi-threaded programs be predictable.

  • the comparison happens twice - faoxis