What is thread deadlock
Deadlock is a kind of blocking phenomenon caused by two or more processes (threads) competing for resources or communicating with each other during the execution process. If there is no external force, they will not be able to move forward. At this time, the system is said to be in a deadlock state or the system generates a deadlock. These processes (threads) that are always waiting for each other are called deadlock processes (threads).
Multiple threads are blocked at the same time, and one or all of them are waiting for a resource to be released. Because the thread is blocked indefinitely, it is impossible for the program to terminate normally.
As shown in the figure below, thread A holds resource 2 and thread B holds resource 1. Both of them want to apply for each other's resources at the same time, so the two threads will wait for each other and enter A deadlock state.
thread deadlock
Here is an example to illustrate the thread deadlock. The code simulates the deadlock situation in the figure above (the code comes from the output result of the beauty of concurrent programming
public class DeadLockDemo { private static Object resource1 = new Object();//Resource 1 private static Object resource2 = new Object();//Resource 2 public static void main(String[] args) { new Thread(() -> { synchronized (resource1) { System.out.println(Thread.currentThread() + "get resource1"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread() + "waiting get resource2"); synchronized (resource2) { System.out.println(Thread.currentThread() + "get resource2"); } } }, "Thread 1").start(); new Thread(() -> { synchronized (resource2) { System.out.println(Thread.currentThread() + "get resource2"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread() + "waiting get resource1"); synchronized (resource1) { System.out.println(Thread.currentThread() + "get resource1"); } } }, "Thread 2").start(); } }
Output results
Thread[Thread 1,5,main]get resource1 Thread[Thread 2,5,main]get resource2 Thread[Thread 1,5,main]waiting get resource2 Thread[Thread 2,5,main]waiting get resource1
Thread A obtains the monitor lock of resource1 through synchronized (resource1), and then through Thread.sleep(1000); let thread A sleep for 1s to let thread B get the CPU execution right, and then get the monitor lock of resource2. Thread A and thread B start to attempt to obtain each other's resources after the end of sleep, and then the two threads will fall into A state of waiting for each other, which also creates A deadlock. The above example meets the four necessary conditions for deadlock generation.
What are the four necessary conditions for deadlock
(1) Mutually exclusive condition: a thread (process) is exclusive to the allocated resources, that is, a resource can only be occupied by a thread (process) until it is released by the thread (process)
(2) Request and hold condition: when a thread (process) is blocked due to the resource occupied by the request, it will keep the acquired resource.
(3) Condition of not depriving: the resources obtained by a thread (process) cannot be forcibly deprived by other threads before the end of use. Resources can only be released after their own use.
(4) Loop waiting condition: when deadlock occurs, the waiting thread (process) must form a loop (similar to the loop), causing permanent blocking
How to avoid thread deadlock
We only need to destroy one of the four conditions for deadlock.
Destroy mutually exclusive condition
We can't break this condition, because we use locks to make them mutually exclusive (critical resources need mutually exclusive access).
Destroy request and hold condition
Request all resources at once.
Destroy the condition of non deprivation
When the thread occupying part of the resource further applies for other resources, if it fails to do so, it can actively release the resources it occupies.
Break cycle waiting condition
Prevention depends on the orderly application of resources. Apply for resources in a certain order, and release resources in reverse order. Break the cycle waiting condition.
We change the code of thread 2 to the following so as to avoid deadlock.
new Thread(() -> { synchronized (resource1) { System.out.println(Thread.currentThread() + "get resource1"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread() + "waiting get resource2"); synchronized (resource2) { System.out.println(Thread.currentThread() + "get resource2"); } } }, "Thread 2").start();
Output results
Thread [thread 1,5,main]get resource1 let's analyze why the above code avoids deadlock?
Let's analyze why the above code avoids deadlock? Welcome to pay attention to gongzhonghao: programmers follow the trend, get a summary of Java interview questions from a large factory + learning mind map of knowledge points + a summary of Java core knowledge points in a 300 page pdf document!
Thread 1 first obtains the monitor lock of resource1, and then thread 2 cannot obtain it. Then thread 1 obtains the monitor lock of resource 2, which can be obtained. Then thread 1 releases the occupation of the monitor lock of resource1 and resource2, and thread 2 can execute when it is acquired. In this way, the waiting condition of breaking cycle is broken, so deadlock is avoided.