Java deadlock method instance discovered through programming using the ThreadMXBean class

Source: Internet
Author: User
Tags stack trace trim

A deadlock means that two or more actions are always waiting for other actions to complete, so that all actions are always blocked. It is very difficult to detect deadlocks in the development phase, and to remove deadlocks, you often need to restart the program. Worse, deadlocks usually occur in the production process with the heaviest load, and it is very difficult to find them during testing. The reason for this is that all possible intersections between test threads are unrealistic. Although some static analysis libraries can help us find possible deadlocks, it is necessary to detect deadlocks at runtime and obtain useful information, so that we can solve this problem, restart the program, or do something else.

Use the ThreadMXBean class in programming to detect deadlocks

Java 5 introduces the ThreadMXBean interface, which provides a variety of methods to monitor threads. I recommend that you understand all these methods, because they provide you with a lot of useful operations when you are not using external tools, so that you can monitor program performance. Here, the method we are interested in is findMonitorDeadlockedThreads. If you have used Java 6, the corresponding method is findDeadlockedThreads. The difference between the two is that findDeadlockedThreads can also detect the deadlock caused by the owner locks (java. util. concurrent), while findMonitorDeadlockedThreads can only detect monitor locks (for example, synchronous blocks ). Since the old version is retained only for compatibility considerations, I will use the new version. Here, the idea of programming is to encapsulate the periodic detection of deadlocks into a reusable component, and then we only need to start it and follow it.

One way to implement scheduling is through the executor framework, that is, a group of well-abstracted and easy-to-use multi-threaded classes.

The code is as follows: Copy code
ScheduledExecutorService schedors = Executors. newScheduledThreadPool (1 );
This. Schedrate. scheduleAtFixedRate (deadlockCheck, period, period, unit );



It is that simple. After we set a specific time by selecting the cycle and time unit, we get a thread for periodic calls. Next, we want to extend the functionality so that users can provide the behavior triggered when the program detects a deadlock. Finally, we need a method to receive a series of objects used to describe all threads in a deadlock.

The code is as follows: Copy code
Void handleDeadlock (final ThreadInfo [] deadlockedThreads );



Now, the deadlock detection class is ready.

The code is as follows: Copy code
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. Schedrate. scheduleAtFixedRate (
This. deadlockCheck, this. period, this. period, this. unit );
  }
}


Let's try it. First, we need to create a handler to output the information of the deadlock thread to System. err. In actual scenarios, we can use it to send emails, for example:

The code is as follows: Copy code
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 repeats in all stack traces and prints the corresponding stack trace for each thread information. In this way, we can accurately know the waiting position and object of each thread. But this method has a defect-when a thread is only waiting for a while, it may be treated as a temporary deadlock, which leads to an error alarm. Because of this, when we handle deadlocks, the original thread cannot continue to exist, and the findDeadlockedThreads method will return no such thread. To avoid possible NullPointerException, we need to be cautious about this situation. Finally, let's create a deadlock to see how the system runs.

The code is as follows: Copy code
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:

The code is as follows: Copy code
Thread1 acquired lock1
Thread2 acquired lock2
Deadlock detected!
"Thread-1" Id = 11 BLOCKED on java. lang. Object @ 68ab95e6 owned by "Thread-0" Id = 10
Deadlock. DeadlockTester $ 2.run( DeadlockTester. java: 42)
Java. lang. Thread. run (threads. 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 (threads. java: 662)



Remember, the deadlock detection overhead may be very high. You need to use your program to test whether you really need the deadlock detection and how often it takes to detect the deadlock. I suggest that the deadlock detection interval be at least several minutes, because more frequent detection does not make much sense, because we do not have a recovery plan, all we can do is debug and handle errors or restart the program and pray that no deadlock will occur again.

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.