Deadlocks

Ensuring that resources are used correctly between threads is easy in Java. Usually, it just takes the use of the synchronized keyword before a method. Because Java makes it seem so easy and painless to coordinate thread access to resources, the synchronized keyword tends to get used liberally. Up to and including Java 1.1, this was the attitude even from Sun. You can still see in the earlier defined classes (e.g., java.util.Vector) that all methods that update instance variables are synchronized. From JDK 1.2, the engineers at Sun became more aware of performance, and are now more careful to avoid synchronizing willy-nilly. Instead, many classes are built unsynchronized but are provided with synchronized wrappers (see the later section Section 10.4.1).

Synchronizing methods liberally may seem like good safe programming, but it is a sure recipe for reducing performance at best, and creating deadlocks at worst. The following Deadlock class illustrates the simplest form of race condition leading to deadlock. Here, the class Deadlock is Runnable. The run() method just has a short half-second delay and then calls hello( ) on another Deadlock object. The problem comes from the combination of the following three factors:

  • Both run( ) and hello( ) are synchronized

  • There is more than one thread

  • The sequence of execution does not guarantee that monitors are locked and unlocked in correct order

The main( ) method accepts one optional parameter to set the delay in milliseconds between ...

Get Java Performance Tuning now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.