The special type of multitasking related error to avoid is deadlocks. Deadlocks occur when two threads have a cyclic dependency on a pair of synchronized objects.

For example, suppose one thread enters the pipe of object X and another thread enters the pipe of object Y. If the thread of X tries to call the synchronous method of Y, it will be locked as expected. The thread of Y also wants to call some synchronous method of X. The thread waits forever, because in order to reach X, it must release its lock of Y so that the first thread can complete. Deadlocks are difficult errors to debug because: · In general, they occur infrequently and only when the two-thread time slots coincide. · It may contain more than two threads and synchronization objects (that is, deadlocks can occur when there is a more complex sequence of events than in the example just described).

To fully understand a deadlock, it is useful to observe its behavior. The following example generates two classes, A and B, with foo() and bar() methods, respectively. Both methods have a short pause before calling methods of other classes. The main class, named Deadlock, creates instances of A and B, and then starts A second thread to set up the Deadlock environment. The foo() and bar() methods use sleep() to force deadlocks to occur.

// An example of deadlock. 
class A { 
 synchronized void foo(B b) { 
 String name = Thread.currentThread().getName(); 
 System.out.println(name + " entered A.foo"); 
 try { 
 Thread.sleep(1000); 
 } catch(Exception e) { 
 System.out.println("A Interrupted"); 
 } 
 System.out.println(name + " trying to call B.last()"); 
 b.last(); 
 } 
 synchronized void last(a) { 
 System.out.println("Inside A.last"); }}class B { 
 synchronized void bar(A a) { 
 String name = Thread.currentThread().getName(); 
 System.out.println(name + " entered B.bar"); 
 try { 
 Thread.sleep(1000); 
 } catch(Exception e) { 
 System.out.println("B Interrupted"); 
 } 
 System.out.println(name + " trying to call A.last()"); 
 a.last(); 
 } 
 synchronized void last(a) { 
 System.out.println("Inside A.last"); }}class Deadlock implements Runnable { 
 A a = new A(); 
 B b = new B(); 
 Deadlock() { 
 Thread.currentThread().setName("MainThread"); 
 Thread t = new Thread(this."RacingThread"); 
 t.start(); 
 a.foo(b); // get lock on a in this thread. 
 System.out.println("Back in main thread"); 
 } 
 public void run(a) { 
 b.bar(a); // get lock on b in other thread. 
 System.out.println("Back in other thread"); 
 } 
 public static void main(String args[]) { 
 newDeadlock(); }}Copy the code

After running the program, the output is as follows:

MainThread entered A.foo 
RacingThread entered B.bar 
MainThread trying to call B.last() 
RacingThread trying to call A.last() 
Copy the code

Because the program is deadlocked, you need to press Ctrl-C to end the program. Press Ctrl-break on a PC (or Ctrl-\ under Solaris) and you can see the full thread and pipe buffer heap. You can see that the RacingThread is holding onto pipe B while waiting for pipe A, and the MainThread is holding onto pipe A while waiting for pipe B.

The program never ends. As this example illustrates, your multithreaded programs are often locked, and deadlocks are the first thing you should check for.