|
The most dreaded situation in a Java program with multiple threads is the deadlock. This situation typically occurs when two (or more) threads are blocked, with each waiting for an object lock which the other thread is holding. This can happen in various situations. The simplest one to imagine is with two threads. Listing 12.6 shows a class Reminder with two methods goHome() and goToOffice(). Each of these methods has a synchronized code and need locks on two objects myCar and myHome for successful completion. Acquiring just one lock is not sufficient.

The Reminder
class has a potential of causing a deadlock when multiple threads will try to
execute its run method. Let us see how this can happen by actually starting two
threads on the same instance of Reminder. In the following code, the class ThreadTester is
creating two threads on reminder object and starting it.
public class ThreadTester {
public static void main(String[] args) {
Reminder reminder = new Reminder();
Thread thread1 = new Thread(reminder);
Thread thread2 = new Thread(reminder);
thread1.start();
thread2.start();
}
}
One possible scenario is thread1 starts executing first. It will start executing the run()method. Since initially the variable wantToGoHome will be true, thread1 will start executing the goHome() method. With the synchronized (myCar), it will acquire the lock on myCar object and then it will go to sleep for 1000 milliseconds. It is likely that thread2 will get a chance to run. Now wantToGoHome is false and hence it will start executing the goToOffice method. With the synchronized (myHome), it will acquire the lock on myHome object and then it too will go to sleep for 1000 milliseconds. Meantime thread1 will probably wake up and will encounter the second synchronized block in goHome().It will see the synchronized (myHome) and it try to acquire the lock on myHome object. But now the myHome object’s lock is already held with thread2 which is sleeping. So thread1 will be blocked on lock for myHome. Eventually thread2 wakes up and it sees the second synchronized block in goToOffice() method it was executing - synchronized (myCar) {}. Now it will try to acquire the lock on myCar object. However, thread1 is already holding the lock. So thread2 will also be blocked on lock for myHome.
Thus thread1 will hold myCar’s lock and block to get myHome’s lock. At the same time, thread2 will hold myHome’s lock and block to get myCar’s lock. Both will never give up the lock they are holding. In that case you will probably get the output as:
Thread-1 has myCar's lock and wants myHome's lock
Thread-2 has myHome's lock and wants myCar's lock
![]() |
Figure 12.12 Deadlocked threads Thread-1 and Thread-2 waiting forever to get the locks held by each other
|
|
Since thread scheduler guarantees nothing, you cannot say for sure that ThreadTester will always cause the deadlock. It is possible that thread1 will complete the execution before thread2 even get to execute. In that case, deadlock will not happen. But you can predict the possibility of deadlock by looking at the code and the class Reminder in listing 12. has one. For exam, you need to understand how deadlock can cause threads to be blocked forever. Blocking is one of the conditions that prevent thread execution (objective 7.2). |
Even when there is a little possibility of deadlock in your code, bear in mind that - deadlock is something you never want to happen. There are number of ways to avoid deadlocks. One simple way is to acquire the locks in a predetermined fashion so that a thread will never block for a lock which it will get only when it releases one of the locks it is holding. For instance, in our example if both goHome() and goToOffice() methods should acquire the locks in same sequence. Either both should acquire the myCar’s lock first followed by the myHome’s lock. Or they both should acquire myHome’s lock first and then myCar’s lock. In that case, the chance of deadlock is minimal. The detailed study of strategies to avoid deadlocks is beyond the scope of this book. However, you may need to learn them whenever you do the deeper study of Java threading.