Java Reference
In-Depth Information
Solution 85: Lazy Initialization
This program looks straightforward, if a bit strange. The static field initialized is initially set to
false . Then the main thread creates a background thread whose run method sets initialized to
true . The main thread starts the background thread and waits for it to complete by calling join .
Once the background thread has completed, there can be no doubt that initialized has been set to
TRue . Then and only then does the main thread invoke main , which prints the value of initialized .
Surely the program must print true ? If only it were so. If you ran the program, you found that it
prints nothing; it just hangs.
In order to understand the behavior of this program, we have to simulate its initialization in detail.
When a thread is about to access a member of a class, the thread checks to see if the class has been
initialized. Ignoring serious errors, there are four possible cases [JLS 12.4.2]:
1.
The class is not yet initialized.
2.
The class is being initialized by the current thread: a recursive request for initialization.
3.
The class is being initialized by some thread other than the current thread.
4.
The class is already initialized.
When the main thread invokes Lazy.main , it checks whether the class Lazy has been initialized. It
hasn't (case 1), so the thread records that initialization is now in progress and begins to initialize the
class. As per our previous analysis, the main thread now sets initialized to false , creates and
starts a background thread whose run method sets initialized to TRue , and waits for the
background thread to complete. Then the fun begins.
The background thread invokes its run method. Before the thread sets Lazy.initialized to true ,
it too checks whether the class Lazy has been initialized. This time, the class is currently being
initialized by another thread (case 3). Under these circumstances, the current thread, which is the
background thread, waits on the Class object until initialization is complete. Unfortunately, the
thread that is doing the initialization, the main thread, is waiting for the background thread to
complete. Because the two threads are now waiting for each other, the program is deadlocked.
That's all there is to it, and what a pity it is.
There are two ways to fix the problem. By far the best way is not to start any background threads
during class initialization: Sometimes, two threads aren't better than one. More generally, keep
class initialization as simple as possible. A second way to fix the problem is to allow the main
thread to finish initializing the class before waiting for the background thread:
// Bad way to eliminate the deadlock. Complex and error prone.
public class Lazy {
 
 
Search WWH ::




Custom Search