How to programmatically discover Java deadlocks

Source: Internet
Author: User

This article is translated by Importnew-rookie_sam from Dzone. Welcome to join the translation team. Reproduced please see at the end of the request.

Deadlock means that two or more actions are waiting for other actions to complete and all actions are always in a blocked state. It is very difficult to detect deadlocks during the development phase, and it is often necessary to restart the program to unlock the deadlock. To make things worse, deadlocks usually occur in the most heavily loaded production process, and it is not easy to find them in the test. The reason for this is that all possible intersections between test threads are unrealistic. Although there are some static analysis libraries that can help us discover the possible deadlocks, we still need to detect deadlocks at runtime and get useful information to solve this problem or to restart the program, or to do something else.

Using the Threadmxbean class to detect deadlocks in programming

Java 5 introduces the Threadmxbean interface, which provides a variety of methods for monitoring threads. I recommend that you understand all of these methods, because when you are not using external tools, they provide you with many useful actions to monitor program performance. Here, we are interested in the method is Findmonitordeadlockedthreads, if you are using Java 6, the corresponding method is finddeadlockedthreads. The difference between the two is that the finddeadlockedthreads can also detect the owner Locks (java.util.concurrent) causes a deadlock, and findmonitordeadlockedthreads can only detect monitor locks (for example, a sync block). Because the method of preserving the old version is only for compatibility reasons, I will use the new version of the method. Here, the idea of programming is to encapsulate the periodic detection of deadlocks into a reusable component, and then we just have to start it and go with it.

One way to implement scheduling is through an executor framework, a set of well-abstracted and easy-to-use multithreaded classes.

12 ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);this.scheduler.scheduleAtFixedRate(deadlockCheck, period, period, unit);

It is that simple, after we set a specific time by selecting a period and a time unit, we get a thread that is periodically called. Next, we want to extend the functionality to allow the user to provide the behavior that triggers when the program detects a deadlock. Finally, we need a way to receive a series of objects that describe all the threads in the deadlock.

1 voidhandleDeadlock(finalThreadInfo[] deadlockedThreads);

Now, implementing the deadlock detection class is ready.

123456789101112131415161718192021222324252627282930313233343536373839 public interface DeadlockHandler {  void handleDeadlock(final ThreadInfo[] deadlockedThreads);}public class DeadlockDetector {  private final DeadlockHandler deadlockHandler;  private final long period;  private final TimeUnit unit;  private final ThreadMXBean mbean = ManagementFactory.getThreadMXBean();  private final ScheduledExecutorService scheduler =   Executors.newScheduledThreadPool(1);  final Runnable deadlockCheck = new Runnable() {    @Override    public void run() {      long[] deadlockedThreadIds = DeadlockDetector.this.mbean.findDeadlockedThreads();      if (deadlockedThreadIds != null) {        ThreadInfo[] threadInfos =         DeadlockDetector.this.mbean.getThreadInfo(deadlockedThreadIds);        DeadlockDetector.this.deadlockHandler.handleDeadlock(threadInfos);      }    }  };  public DeadlockDetector(final DeadlockHandler deadlockHandler,     final long period, final TimeUnit unit) {    this.deadlockHandler = deadlockHandler;    this.period = period;    this.unit = unit;  }  public void start() {    this.scheduler.scheduleAtFixedRate(    this.deadlockCheck, this.period, this.period, this.unit);  }}

Let's try it. First, we will create a handler used to output the deadlock thread to the System.err. In a real-world scenario, we can use it to send messages, such as:

123456789101112131415161718192021222324252627 public class DeadlockConsoleHandler implements DeadlockHandler {  @Override  public void handleDeadlock(final ThreadInfo[] deadlockedThreads) {    if (deadlockedThreads != null) {      System.err.println("Deadlock detected!");      Map<Thread, StackTraceElement[]> stackTraceMap = Thread.getAllStackTraces();      for (ThreadInfo threadInfo : deadlockedThreads) {        if (threadInfo != null) {          for (Thread thread : Thread.getAllStackTraces().keySet()) {             if (thread.getId() == threadInfo.getThreadId()) {              System.err.println(threadInfo.toString().trim());              for (StackTraceElement ste : thread.getStackTrace()) {                  System.err.println("t" + ste.toString().trim());              }            }          }        }      }    }  }}

This process is repeated in all stack traces and the corresponding stack traces are printed for each thread information. In this way, we can know exactly where each thread waits and what the object is. But there is a flaw in this approach-when a thread waits only temporarily, it may be treated as a temporary deadlock, triggering an erroneous alert. For this reason, when we handle deadlocks, the original thread cannot continue to exist and the Finddeadlockedthreads method returns no such thread. In order to avoid possible nullpointerexception, we need to be wary of this situation. Finally, let's get a deadlock to see how the system works.

123456789101112131415161718192021222324252627282930313233343536 DeadlockDetector deadlockDetector = new DeadlockDetector(new DeadlockConsoleHandler(), 5, TimeUnit.SECONDS);deadlockDetector.start(); final Object lock1 = new Object();final Object lock2 = new Object();Thread thread1 = new Thread(new Runnable() {  @Override  public void run() {    synchronized (lock1) {      System.out.println("Thread1 acquired lock1");      try {        TimeUnit.MILLISECONDS.sleep(500);      } catch (InterruptedException ignore) {      }      synchronized (lock2) {        System.out.println("Thread1 acquired lock2");      }    }  }});thread1.start();Thread thread2 = new Thread(new Runnable() {  @Override  public void run() {    synchronized (lock2) {      System.out.println("Thread2 acquired lock2");      synchronized (lock1) {        System.out.println("Thread2 acquired lock1");      }    }  }});thread2.start();

Output:

123456789 Thread1 acquired lock1Thread2 acquired lock2Deadlock detected!“Thread-1” Id=11 BLOCKED on java.lang.Object@68ab95e6 owned by “Thread-0” Id=10deadlock.DeadlockTester$2.run(DeadlockTester.java:42)  java.lang.Thread.run(Thread.java:662)“Thread-0” Id=10 BLOCKED on java.lang.Object@58fe64b9 owned by “Thread-1” Id=11 deadlock.DeadlockTester$1.run(DeadlockTester.java:28) java.lang.Thread.run(Thread.java:662)

Remember, the overhead of deadlock detection can be very large, you need to use your program to test whether you really need deadlock detection and how often to detect. I recommend a deadlock detection interval of at least a few minutes, because more frequent detection doesn't make much sense, because we don't have a recovery plan, and all we can do is debug and handle errors or restart programs and pray that deadlocks won't happen again. If you have any good suggestions or questions about solving a deadlock problem, please leave a comment below.

Original link: Dzone translation: Importnew.com-rookie_sam
Link: http://www.importnew.com/15307.html

How to programmatically discover Java deadlocks

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.