63
votes

Long time ago, I saved a sentence from a Java reference book: "Java has no mechanism to handle deadlock. it won't even know deadlock occurred." (Head First Java 2nd Edition, p.516)

So, what is about it? Is there a way to catch deadlock case in Java? I mean, is there a way that our code understands a deadlock case occurred?

16
Is Java different from other languages in this regard? - Michael Burr
it's not impossible to detect a deadlock - it's just quite difficult - 1800 INFORMATION
for example - most databases will detect deadlocks - 1800 INFORMATION
Java may not have a mechanism to 'handle' deadlocks, but it DOES know about deadlocks. Read my post bellow and I explain how... - Jeach
Isn't this question a duplicate of: stackoverflow.com/questions/1102359 - Tiago Cogumbreiro

16 Answers

82
votes

Since JDK 1.5 there are very useful methods in the java.lang.management package to find and inspect deadlocks that occurs. See the findMonitorDeadlockedThreads() and findDeadlockedThreads() method of the ThreadMXBean class.

A possible way to use this is to have a separate watchdog thread (or periodic task) that does this.

Sample code:

  ThreadMXBean tmx = ManagementFactory.getThreadMXBean();
  long[] ids = tmx.findDeadlockedThreads();
  if (ids != null) {
     ThreadInfo[] infos = tmx.getThreadInfo(ids, true, true);
     System.out.println("The following threads are deadlocked:");
     for (ThreadInfo ti : infos) {
        System.out.println(ti);
     }
  }
18
votes

JConsole is able to detect deadlocks in a running application.

11
votes

JDK 5 and 6 will dump held lock information in a full thread dump (obtained with kill -3, jstack, jconsole, etc). JDK 6 even contains information about ReentrantLock and ReentrantReadWriteLock. It is possible from this information to diagnose a deadlock by finding a lock cycle: Thread A holds lock 1, Thread B holds lock 2, and either A is requesting 2 or B is requesting 1. From my experience, this is usually pretty obvious.

Other analysis tools can actually find potential deadlocks even if they don't occur. Thread tools from vendors like OptimizeIt, JProbe, Coverity, etc are good places to look.

10
votes

Note that there is a type of deadlock using the concurrent package that is very hard to debug. That is where you have a ReentrantReadWriteLock and one thread grabs the read lock and then (say) tries to enter a monitor held by some other thread that is also waiting to grab the write lock. What makes it especially hard to debug is that there is no record of who has entered a read lock. It is simply a count. The thread might even have thrown an exception and died leaving the read count non-zero.

Here is a sample deadlock that the findDeadlockedThreads method mentioned earlier won't get:

import java.util.concurrent.locks.*;
import java.lang.management.*;

public class LockTest {

    static ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    public static void main(String[] args) throws Exception {
        Reader reader = new Reader();
        Writer writer = new Writer();
        sleep(10);
        System.out.println("finding deadlocked threads");
        ThreadMXBean tmx = ManagementFactory.getThreadMXBean();
        long[] ids = tmx.findDeadlockedThreads();
        if (ids != null) {
            ThreadInfo[] infos = tmx.getThreadInfo(ids, true, true);
            System.out.println("the following threads are deadlocked:");
            for (ThreadInfo ti : infos) {
                System.out.println(ti);
            }
        }
        System.out.println("finished finding deadlocked threads");
    }

    static void sleep(int seconds) {
        try {
            Thread.currentThread().sleep(seconds*1000);
        } catch (InterruptedException e) {}
    }

    static class Reader implements Runnable {
        Reader() {
            new Thread(this).start();
        }
        public void run() {
            sleep(2);
            System.out.println("reader thread getting lock");
            lock.readLock().lock();
            System.out.println("reader thread got lock");
            synchronized (lock) {
                System.out.println("reader thread inside monitor!");
                lock.readLock().unlock();
            }
        }
    }

    static class Writer implements Runnable {
        Writer() {
            new Thread(this).start();
        }
        public void run() {
            synchronized (lock) {
                sleep(4);
                System.out.println("writer thread getting lock");
                lock.writeLock().lock();
                System.out.println("writer thread got lock!");
            }
        }
    }
}
6
votes

In general java does not offer deadlock detection. The synchronized keyword and built in monitors make it somewhat more difficult to reason about deadlock than in languages with explicit locking.

I would suggest migrating to using java.util.concurrent.Lock locks and the like in order to make your locking schemes easier to reason about. In fact you could easily make your own implementation of the lock interface with deadlock detection. The algorithm is to basically traverse the lock dependency graph and look for a cycle.

5
votes

Java can detect deadlocks (although not at run-time, it can still diagnose and report it).

For example, when using a slightly modified version of 'Saurabh M. Chande' code bellow (changed it to Java and added some timing to guarantee a lock on each run). Once you run it and it deadlocks, if you type:

kill -3 PID   # where 'PID' is the Linux process ID

It will generate a stack dump, which will include the following information:

Found one Java-level deadlock:
=============================
"Thread-0":
     waiting to lock monitor 0x08081670 (object 0x7f61ddb8, a Deadlock$A),
     which is held by "main"
"main":
      waiting to lock monitor 0x080809f0 (object 0x7f61f3b0, a Deadlock$B),
      which is held by "Thread-0"
5
votes

Deadlocks can be avoided if you follow a simple rule: have all threads claim and release their locks in the same order. In this way, you never get into a situation where a deadlock can occur.

Even the dining philosophers problem can be seen as a violation of this rule as it uses relative concepts of left and right spoon which result in different threads using different allocation orders of the spoons. If the spoons were numbered uniquely and the philosophers all tried to get the lowest numbered spoon first, deadlock would be impossible.

In my opinion, prevention is better than cure.

This is one of the two guidelines I like to follow to ensure threads work properly. The other is ensuring each thread is solely responsible for its own execution as it's the only one fully aware of what it's doing at any point in time.

So that means no Thread.stop calls, use a global flag (or message queue or something like that) to tell another thread you want action taken. Then let that thread do the actual work.

4
votes

If you are on Java 5 you can call the method findMonitorDeadlockedThreads() on the ThreadMXBean which you can get through a call of java.lang.management.ManagementFactory.getThreadMXBean(). This will find deadlocks caused by object monitors only. On Java 6 there's findDeadlockedThreads() which will also find deadlocks caused by "ownable synchronizers (for example ReentrandLock and ReentrantReadWriteLock).

Be aware that it will probably be expensive to call these methods, so they should be used for troubleshooting purposes only.

3
votes

Not exactly what you asked, but when a deadlock does occur, you can do a "kill -3" on the process id and it dumps a thread dump to stdout. Also, the 1.6 jvm has some tools to do the same thing in a gui manner.

3
votes

If you are running from the command-line and you suspect that you are deadlocked, try ctrl+break in windows (ctrl+\ in unix) to get a thread dump. See http://java.sun.com/javase/6/webnotes/trouble/TSG-VM/html/gbmps.html

3
votes

Dr. Heinz Kabutz of JavaSpecialists has written an entertaining and informative newsletter issue on Java deadlocks and describes something called a ThreadMXBean in another newsletter issue. Between those, you should get a good idea of the issues and some pointers to doing your own instrumentation.

2
votes

If you're debugging in eclipse, you can pause the application (select the app in the debug view and the little || button on the debug toolbar) and then it can report deadlocks.

See http://runnerwhocodes.blogspot.com/2007/10/deadlock-detection-with-eclipse.html for an example.

1
votes

Java 1.8 onwards, you can easily find if your program has a deadlock by using jcmd command on your terminal.

  1. Run jcmd on your terminal: It lists all the programs (PID and name) which are using Java.
  2. Now, run jcmd <PID> Thread.print: This will print the thread dump on your console and will also print if your program has a deadlock.

You can analyse your Java program with more jcmd options listed by command jcmd <PID> help

0
votes

Java 5 introduced ThreadMXBean - an interface that provides various monitoring methods for threads. ... The difference is that findDeadlockedThreads can also detect deadlocks caused by owner locks (java.util.concurrent), while findMonitorDeadlockedThreads can only detect monitor locks (i.e. synchronized blocks)

Or you can detect it programatically, refer this https://dzone.com/articles/how-detect-java-deadlocks

-1
votes

After so long, i am able to write the simplest example of Deadlock. Comments are welcome.

Class A
{
  synchronized void methodA(B b)
  {
    b.last();
  }

  synchronized void last()
  {
    SOP(“ Inside A.last()”);
  }
}

Class B
{
  synchronized void methodB(A a)
  {
    a.last();
  }

  synchronized void last()
  {
    SOP(“ Inside B.last()”);
  }
}


Class Deadlock implements Runnable 
{
  A a = new A(); 
  B b = new B();

  // Constructor
  Deadlock()
  {
    Thread t = new Thread(); 
    t.start();
    a.methodA(b);
  }

  public void run()
  {
    b.methodB(a);
  }

  public static void main(String args[] )
  {
    new Deadlock();
  }
}
-4
votes

you have to modify the code a little bit in the Deadlock Class

   Deadlock() {
    Therad t = new Thread(this); // modified
    t.start();
    System.out.println(); //any instruction to delay
    a.methodA(b);
}

Also the above code will not always cause a dead lock, only some times it may happen.