Troubleshooting: using control + break to solve thread deadlock
brief introduction
If we encounter thread deadlock in the program, how to solve it?
This article will start from a practical example and uncover the veil of Java problem solving step by step.
Deadlock code
People who have written Java multithreaded programs should know that a very important thing in multithreading is state synchronization, but in the process of state synchronization, carelessness may lead to deadlock.
One of the simplest deadlock situations is that thread1 occupies resource 1 and then has to obtain resource 2 When thread2 occupies resource 2, it has to obtain resource 1.
For example:
public class TestDeadLock {
public static Object lock1= new Object();
public static Object lock2= new Object();
public static void main(String[] args) {
Runnable runnable1= ()-> {
System.out.println("in lock1");
synchronized(lock1){
System.out.println("Lock1 lock obj1");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized(lock2){
System.out.println("Lock1 lock obj2");
}
}
};
Runnable runnable2= ()-> {
System.out.println("in lock2");
synchronized(lock2){
System.out.println("Lock2 lock obj2");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized(lock1){
System.out.println("Lock2 lock obj1");
}
}
};
Thread a = new Thread(runnable1);
Thread b = new Thread(runnable2);
a.start();
b.start();
}
}
We run the above code:
in lock1
Lock1 lock obj1
in lock2
Lock2 lock obj2
When the lock cycle waiting is sent, the program cannot be executed, and a deadlock is sent.
Control + break command
When the code is very simple, we can easily analyze the cause of deadlock, but if it is in a very large online project, it is not so easy to analyze the code.
How?
Today, I'll teach you a method to use the control + break command.
Control + break means control + backslash in Linux, and the control + break button in windows.
Of course, there is a more general way to use:
Kill - quit PID command.
We use the JPS command to obtain the process ID of executing the Java program, and then execute the kill - quit command.
After execution, we will find that the running java process will output some additional logs, which are the key factor for us to find deadlock.
Note that this kill command does not terminate the program.
There are a lot of output contents. We will explain them part by part.
Full thread dump
The first part of the log is full thread dump, which contains the status information of all threads in the JVM.
Let's look at two key thread information in our code:
"Thread-0" #13 prio=5 os_prio=31 cpu=4.86ms elapsed=230.16s tid=0x00007fc926061800 nid=0x6403 waiting for monitor entry [0x0000700008d6a000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.flydean.TestDeadLock.lambda$main$0(TestDeadLock.java:21)
- waiting to lock <0x0000000787e868f0> (a java.lang.Object)
- locked <0x0000000787e868e0> (a java.lang.Object)
at com.flydean.TestDeadLock$$Lambda$14/0x0000000800b69840.run(UnkNown Source)
at java.lang.Thread.run(java.base@14.0.1/Thread.java:832)
"Thread-1" #14 prio=5 os_prio=31 cpu=4.32ms elapsed=230.16s tid=0x00007fc924869800 nid=0x6603 waiting for monitor entry [0x0000700008e6d000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.flydean.TestDeadLock.lambda$main$1(TestDeadLock.java:36)
- waiting to lock <0x0000000787e868e0> (a java.lang.Object)
- locked <0x0000000787e868f0> (a java.lang.Object)
at com.flydean.TestDeadLock$$Lambda$15/0x0000000800b69c40.run(UnkNown Source)
at java.lang.Thread.run(java.base@14.0.1/Thread.java:832)
The above output lists the thread name, thread priority, CPU time, whether it is a daemon thread, thread ID, thread status and other useful information.
Seeing the above output, we can see that both threads are in blocked state and are waiting for object monitor.
Remember several states of threads? Let's review it again.
Deadlock detection
The next part is the deadlock detection we are most concerned about.
Found one Java-level deadlock:
=============================
"Thread-0":
waiting to lock monitor 0x00007fc926807e00 (object 0x0000000787e868f0,a java.lang.Object),which is held by "Thread-1"
"Thread-1":
waiting to lock monitor 0x00007fc926807f00 (object 0x0000000787e868e0,which is held by "Thread-0"
Java stack information for the threads listed above:
===================================================
"Thread-0":
at com.flydean.TestDeadLock.lambda$main$0(TestDeadLock.java:21)
- waiting to lock <0x0000000787e868f0> (a java.lang.Object)
- locked <0x0000000787e868e0> (a java.lang.Object)
at com.flydean.TestDeadLock$$Lambda$14/0x0000000800b69840.run(UnkNown Source)
at java.lang.Thread.run(java.base@14.0.1/Thread.java:832)
"Thread-1":
at com.flydean.TestDeadLock.lambda$main$1(TestDeadLock.java:36)
- waiting to lock <0x0000000787e868e0> (a java.lang.Object)
- locked <0x0000000787e868f0> (a java.lang.Object)
at com.flydean.TestDeadLock$$Lambda$15/0x0000000800b69c40.run(UnkNown Source)
at java.lang.Thread.run(java.base@14.0.1/Thread.java:832)
Found 1 deadlock.
We can clearly see from the above log that two threads have obtained the locks required by each other, resulting in deadlock.
At the same time, the information of thread stack is listed in detail for our analysis.
Heap information
The last part is the statistics of heap:
Heap
garbage-first heap total 133120K,used 3888K [0x0000000780000000,0x0000000800000000)
region size 1024K,4 young (4096K),0 survivors (0K)
Metaspace used 1122K,capacity 4569K,committed 4864K,reserved 1056768K
class space used 108K,capacity 412K,committed 512K,reserved 1048576K