|
|
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 7 of 7
The other solution is to use an architecture that tends to minimize these sorts of problems. (Various threading architectures will be the subject of the remaining articles in this series.)
There is no magic bullet there. I've seen ads for a couple of products that instrument a VM in a way that, in theory, will detect deadlock and race conditions. The problem, though, is a classic Heisenberg-uncertainty dilemma: there's no way to observe the process without impacting it. If the problem is timing-related, adding a print statement or changing to a debugging version of the VM will change the timing, perhaps eliminating the problem. I haven't actually used any of these products yet, but I remain skeptical.
Another important form of deadlock is not discussed much in the Java-language books: nested-monitor lockout. This problem usually occurs when you call a blocking function from within a synchronized method, and the only way to release the block is to call another synchronized method. The following code demonstrates the problem.
class Notifying_queue
{ // Same class as was described earlier, blocks on dequeue from
// an empty queue.
//...
}
class Black_hole
{
private Notifying_queue queue = new Notifying_queue(5);
public synchronized void put( Object thing )
{ queue.enqueue( thing );
}
public synchronized Object get( )
{ return queue.dequeue();
}
}
Consider what happens when you try to dequeue something from an empty queue:
get() to get the item from the queue.get() is synchronized, so the Black_hole is now locked.get() calls dequeue(), which blocks, waiting for some other thread to enqueue something. get() does not return.put, which we can't do because the Black_hole is locked. That is, any thread that tries to put() will block because the first thread has not returned from get() yet.
The Black_hole now sucks up all threads that try to put() or get() anything. They all block forever.
Depending on where this occurs, the black hole could suck up every thread in your program. Also bear in mind that this problem can occur anytime you have a blocking call (such as a file read) inside a synchronized method.
The only cures are:
In the current situation, you could just not synchronize put(), but that wouldn't work in a more realistic situation where put() accessed fields of the class that were accessed by other methods.
This problem has been known since Java 1.0 was in the early prerelease stage, and several people complained vociferously about it. (The problem is a direct result of the way Java's synchronization works -- the condition variable and mutex are both part of the object and not separate entities --- compounded by the fact that you have to acquire the mutex to wait on the condition.) But as Doug Lea pointed out in a recent e-mail to me:
[the complaints] boiled down to "you tend to like best what you are most used to." Java makes some things that are painful in POSIX easy, and vice-versa. In any case, it is pretty easy to simulate one set of primitives with the other.
That's life, I guess.
The next several articles in this series on threads will present a solution to the problem that decouples the semaphores from the things they guard, but that solution introduces a whole set of additional problems.
Hopefully, I've demonstrated by now that programming in a multithreaded environment isn't as easy as the evangelist types would have you believe. Java provides platform-independent ways to use the two essential synchronization mechanisms: exclusion semaphores and condition variables. It does it in an awkward way, however, that doesn't help much when you're trying to do more than blink your logo in a simple applet. All is not lost, however. Over the next few months, I'll present a library of classes that solve many common threading problems, including some of the ones I've just discussed. Sometimes, I even think of it as fun, but maybe that's because I've been programming too long.