What is a deadlock
Deadlock is very simple to understand, just a word, “jam”. The congested intersection in the picture below can be seen as a deadlock state, cars in four directions have to go forward, but there is only one intersection, only cars in one direction can be allowed to pass, then cars in another direction can pass.
In multi-threading, the traffic flow in four directions can be seen as four threads, and the intersection can be seen as a resource object, four threads have to occupy it, will lead to the normal operation of the program, which is called deadlock, is not very easy to understand it.
The more official explanation for deadlocks is the classic four conditions
1. Mutually exclusive use, that is, when a resource is used by one thread, other threads cannot use it
2. No preemption. The resource requester cannot forcibly seize the resource from the resource possessor, and the resource can only be released by the resource possessor.
3. Request and hold, that is, when the resource requester requests other resources while maintaining the possession of the original resource.
4. Cyclic waiting, that is, there is a waiting queue: P1 occupies P2 resources, P2 occupies P3 resources, and P3 occupies P1 resources. This creates a waiting loop.
When all four conditions are true, a deadlock occurs. Of course, if any of these conditions are broken in a deadlock case, the deadlock will disappear.
Create a deadlock case
public class DeadLock { public static String r1="r1"; public static String r2="r2"; public static void main(String[] args) { Runable1 runable1=new Runable1(); Runable2 runable2=new Runable2(); Thread thread1=new Thread(runable1); Thread thread2=new Thread(runable2); thread1.start(); thread2.start(); } } class Runable1 implements Runnable{ @Override public void run() { try { (DeadLock.r1) { System.out.println("r1 synchronized "); Thread.sleep(3000); Synchronized (DeadLock. R2) {system.out.println (" no r2 only slightly "); Thread.sleep(60 * 1000); } system.out.println (" locked, unable to print "); } }catch (Exception e) { e.printStackTrace(); } } } class Runable2 implements Runnable{ @Override public void run() { try { synchronized (DeadLock.r2){ System. The out. Println (" synchronized lock r2 "); Thread.sleep(3000); Synchronized (DeadLock. R1){system.out.println (" no r1 or no r1 "); Thread.sleep(60 * 1000); } system.out.println (" locked, unable to print "); } }catch (Exception e){ e.printStackTrace(); }}} // Result R1 synchronized locks R1 synchronized locks R2Copy the code
In the example above, r1 and R2 are created, and two thread classes Runable1 and Runable2 are created. Synchronized locks are used to lock resources, so that neither thread releases r1 and R2 until the run method is completed. (Synchronized is used as a lock, and resources in synchronized parentheses are not released until the end of the thread, so they cannot be used by other threads.) Sleep (60*1000) blocks the thread), which causes a deadlock and prevents subsequent statements from being printed.
How to solve the deadlock problem
1. When writing multithreaded operations, it is best not to lock more than one object at a time so that it does not cause deadlocks. The modified code looks like this.
public class DeadLock { public static String r1="r1"; public static String r2="r2"; public static void main(String[] args) { Runable1 runable1=new Runable1(); Runable2 runable2=new Runable2(); Thread thread1=new Thread(runable1); Thread thread2=new Thread(runable2); thread1.start(); thread2.start(); } } class Runable1 implements Runnable{ @Override public void run() { try { synchronized (DeadLock.r1) { System.out.println("r1 synchronized "); Thread.sleep(3000); System. The out. Println (" get r2 "); Thread.sleep(3000); System.out.println(" unlocked, printable "); } }catch (Exception e) { e.printStackTrace(); } } } class Runable2 implements Runnable{ @Override public void run() { try { synchronized (DeadLock.r2){ System. The out. Println (" synchronized lock r2 "); Thread.sleep(3000); System. The out. Println (" get r1 "); Thread.sleep(3000); System.out.println(" unlocked, printable "); } }catch (Exception e){ e.printStackTrace(); }}} // Result R1 synchronized R1 synchronized R2 get R2 get R1 unlocked, print unlocked, printCopy the code
2. If multiple resource objects need to be locked at a time, you can define the lock sequence based on a resource attribute or hashCode value. The following example uses hashCode to define the lock sequence.
public class DeadLock { public static String r1="r1"; public static String r2="r2"; public static void main(String[] args) { Runable1 runable1=new Runable1(); Runable2 runable2=new Runable2(); Thread thread1=new Thread(runable1); Thread thread2=new Thread(runable2); thread1.start(); thread2.start(); } } class Runable1 implements Runnable{ @Override public void run() { try { if (DeadLock.r1.hashCode()>DeadLock.r2.hashCode()) { synchronized (DeadLock.r1) { System.out.println(" synchronized from Runable1 to R1 "); Thread.sleep(3000); Synchronized (DeadLock. R2) {system.out.println (" synchronized of Runable1 "); synchronized (DeadLock. Thread.sleep(3000); } system.out.println (" unlocked, printable "); }}else{synchronized (DeadLock. R2) {system.out.println (" synchronized of Runable1 "); Thread.sleep(3000); Synchronized (DeadLock. R1) {system.out.println ("Runable1 synchronized R2 "); synchronized (DeadLock. Thread.sleep(3000); } system.out.println (" unlocked, printable "); } } }catch (Exception e) { e.printStackTrace(); } } } class Runable2 implements Runnable{ @Override public void run() { try { if (DeadLock.r1.hashCode()<DeadLock.r2.hashCode()) { synchronized (DeadLock.r2) { System.out.println(" synchronized Runable2 "); Thread.sleep(3000); Synchronized (DeadLock. R1) {system.out.println (" synchronized Runable2 "); synchronized (DeadLock. Thread.sleep(3000); } system.out.println (" unlocked, printable "); }}else{synchronized (DeadLock. R1) {system.out.println (" synchronized of Runable2 "); Thread.sleep(3000); Synchronized (DeadLock. R2) {system.out.println (" synchronized Runable2 "); synchronized (DeadLock. Thread.sleep(3000); } system.out.println (" unlocked, printable "); } } }catch (Exception e) { e.printStackTrace(); Runable1 synchronized R1 Runable1 synchronized R2 R1 Runable2 synchronized R2 unlocked, printCopy the code