There's a general problem with code not being executed in the order it's written. In Java, a thread is only obligated to be consistent with itself. An instance
created on one line with new
has to be ready to go on the next. There's no such oblgation to other threads. For instance, if fieldA
is 1 and 'fieldB' is 2 going into this code on thread 1:
fieldA = 5;
fieldB = 10;
and thread 2 runs this code:
int x = fieldA;
int y = FieldB;
x y values of 1 2, 5 2, and 5 10 are all to be expected, but 1 10--fieldB was set and/or picked up before fieldA--is perfectly legal, and likely, as well. So double-checked locking is a special case of a more general problem, and if you work with multiple threads you need to be aware of it, particularly if they all access the same fields.
One simple solution from Java 1.5 that should be mentioned: fields marked volatile
are guaranteed to be read from main memory immediately before being referenced and written immediately after. If fieldA
and fieldB
above were declared volatile
, an x y value of 1 10 would not be possible. If instance
is volatile, double-checked locking works. There's a cost to using volatile
fields, but it's less than synchronizing, so the double-checked locking becomes a pretty good idea. It's an even better idea because it avoids having a bunch of threads waiting to synch while CPU cores are sitting idle.
But you do want to understand this (if you can't be talked out of multithreading). On the one hand you need to avoid timing problems and on the other avoid bringing your program to a halt with all the threads waiting to get into synch blocks. And it's very difficult to understand.