double-checked locking... in the JDK core?!

Here is an example where threads can see half-constructed instances:


class MyReallyDumbType {
   private OtherObject dep;

   MyReallyDumbConstructor() {
      dep = new OtherObject();
      new Thread(new Runnable() {
         public void run() {
            // start modifying dep here
         }
      }
   }
}

Here, without any synchronization or volatile going on, the 2nd thread might have an inconsistent view of the memory modified by the first thread. Although thread 1 sees dep’s reference fully constructed, thread 2 might only have seen the assignment to the dep variable, and not the memory initialized by OtherObject’s constructor.

So in that rare situation, thread 2 sees a partially constructed object.

Going back to the original, bad double-checked lock in Math.random(), the problem is that the first check against the randomNumberGenerator field is not synchronized. The calling thread could see a non-null reference written by another thread that just completed initRNG() and think it doesn’t need to instantiate the RNG. Since there was no synchronization, though, the actual instance might be in an inconsistent state to the calling thread and all bets of correctness are off.