img
. . . .
Display of a value is a good example because it's simple. It's a bad example because it doesn't gain
you anything. Displaying something is an expensive operation, requiring hundreds to thousands of
microseconds. Saving 1 µs by skipping a lock is not going to make a difference in performance,
but it will make your code a little uglier.
A better example of this situation is what's come to be known as double-checked locking (Code
Example 7-6). This is useful in situations where a value is going to be initialized dynamically
exactly once. The naive way of doing this is to have each thread lock a lock and then check to see
if the data has been initialized yet, doing the initialization if not. With double-checked locking you
can skip the lock and look directly at the value in question. If the value is valid, you know it has
been initialized and that you can use it. If the value is invalid (presumably null), you lock the
lock, recheck, and initialize. It is essential that you lock and recheck, as it is always possible for
another thread to be running the same code at the same time.
Example 7-6 Double-Checked Locking
void foo() {
if (!object.initialized) {
synchronized (object) {
if (!object.initialized) {
object.initialize();
object.initialized = true;
}
}
}
use object
}
You will probably never have use of this technique, as its use is so limited. Dynamic initialization
like this is generally avoidable as you normally do initialization statically at load time or possibly
directly from main() before any threads are started. Be very careful when doing this, as it's easy
to do wrong.
Synchronization Problems
A number of things can go wrong when you try to coordinate the interactions of your threads. Not
using synchronization variables is the most obvious and most common. But even when you've
been careful to lock everything in sight, you still may encounter other problems. All of them have
solutions; none of them have perfect solutions.
Deadlocks
A deadlock is a kind of catch-22 in which one thread needs another thread to do something before
it proceeds, and the other thread needs something from the first. So they both sit there, doing
nothing, waiting for each other, forever. This is a bad thing.
A typical deadlock (Figure 7-8; Code Example 7-7) occurs when thread T1 obtains lock M1, and
thread T2 obtains lock M2. Then thread T1 tries to obtain lock M2, while thread T2 tries for lock
M1.
Example 7-7 Deadlock in Java
Search WWH :
Custom Search
Previous Page
Multithreaded Programming with JAVA - Topic Index
Next Page
Multithreaded Programming with JAVA - Bookmarks
Home