Java thread deadlock and its solution

To understand thread deadlock, we must first understand what a deadlock is

 

Deadlock

In layman's terms: Deadlock is a blocking phenomenon caused by competition for resources or due to communication between two or more processes or threads during the execution. If there is no external force, they will not be able to advance.

 

Let’s use a simpler example

 

For example, in this traffic jam example, it can be seen from the figure that cars traveling in four directions are blocking each other. If there is no car in any one direction returning, then a deadlock will be formed.

There are four reasons for deadlock in the above figure:

1. Mutually exclusive conditions: a resource can only be used by one thread at a time. Each road on the map can only allow cars in one direction to pass, so one of the conditions for deadlock is met

2. Request and hold conditions: When a process is blocked by requesting resources, it keeps on holding the acquired resources. It can be seen that cars in each direction on the map are waiting for cars in other directions to evacuate, so the second condition for deadlock is met.

3. Non-deprivation conditions: the resources obtained by the process cannot be deprived forcibly before they are used up. It is assumed here that there is no traffic police, so no one can forcefully request the evacuation of cars in other directions, so the third condition for deadlock is met.

4. Cyclic waiting condition: A kind of cyclic waiting resource relationship is formed between several processes or threads. This is very intuitively expressed in the figure
 

 

Deadlock Java code small example

 

 

 

package huaxin2016_9_9;

public class ThreadDeadlock {
	public static void main(String[] args) throws InterruptedException {
		Object obj1 = new Object();
		Object obj2 = new Object();
		Object obj3 = new Object(); 
		//新建三个线程
		Thread t1 = new Thread(new SyncThread(obj1, obj2), "t1"); 
		Thread t2 = new Thread(new SyncThread(obj2, obj3), "t2"); 
		Thread t3 = new Thread(new SyncThread(obj3, obj1), "t3"); 
		//让线程依次开始
		t1.start(); 
		//让线程休眠
		Thread.sleep(5000);
		t2.start();
		Thread.sleep(5000);
		t3.start();
	} 
} 
class SyncThread implements Runnable{ 
	private Object obj1; 
	private Object obj2;
	//构造函数
	public SyncThread(Object o1, Object o2){ 
		this.obj1=o1;
		this.obj2=o2;
	} 
	@Override
	public void run() {
		//获取并当前运行线程的名称
		String name = Thread.currentThread().getName();
		System.out.println(name + " acquiring lock on "+obj1);
		
		
		synchronized (obj1) { 
			System.out.println(name + " acquired lock on "+obj1); 
			work();
			System.out.println(name + " acquiring lock on "+obj2); 
			synchronized (obj2) { 
				System.out.println(name + " acquired lock on "+obj2); 
				work();
		    } 
			System.out.println(name + " released lock on "+obj2); 
	    } 
		System.out.println(name + " released lock on "+obj1); 
		System.out.println(name + " finished execution.");
	}
	private void work() { 
		try { 
			Thread.sleep(30000); 
		} 
		catch (InterruptedException e) { 
			e.printStackTrace();
		}
	} 
}

The result of the above deadlock small example is

 

 

t1 acquiring lock on java.lang.Object@675d5ed4
t1 acquired lock on java.lang.Object@675d5ed4
t2 acquiring lock on java.lang.Object@7943f708
t2 acquired lock on java.lang.Object@7943f708
t3 acquiring lock on java.lang.Object@46767615
t3 acquired lock on java.lang.Object@46767615
t1 acquiring lock on java.lang.Object@7943f708
t2 acquiring lock on java.lang.Object@46767615
t3 acquiring lock on java.lang.Object@675d5ed4

It can be seen intuitively that t1, t2, and t3 are all requesting resources, but they all maintain their own resources, which causes deadlock.

 

 

solution:

1. To break the mutually exclusive condition, we need to allow the process to access certain resources at the same time. This method is subject to the actual scenario and it is not easy to achieve the condition;

2. Break the non-preemption condition. In this way, you need to allow the process to forcibly seize certain resources from the occupant, or simply understand that the process that occupies the resource can no longer apply for the occupancy of other resources. The application must be released after the resources in hand. It is also difficult to find applicable scenarios;

3. The process applies for all resources before running, otherwise the process cannot enter the ready-to-execute state. This method seems to be useful, but its disadvantage is that it may lead to reduced resource utilization and process concurrency

4. Avoid resource application loops, that is, sort and number resources in advance and assign them according to number. This method can effectively improve resource utilization and system throughput, but it increases system overhead and increases the time that the process takes up resources.

 

(1). The simplest and most commonly used method is to restart the system, but this method is very costly, it means that all the calculation work that has been completed by the process will be wasted, including participation in death. Processes that are locked, and processes that are not involved in the deadlock;

(2). Cancel the process and deprive resources. Terminate the processes participating in the deadlock and recover the resources they occupy, thereby removing the deadlock. At this time, there are two situations: cancel all processes participating in the deadlock at one time and deprive all resources; or gradually cancel the processes participating in the deadlock, and gradually recover the resources occupied by the deadlock process. Generally speaking, when choosing a process to be gradually cancelled, you must follow certain principles. The purpose is to cancel the process with the least cost, such as determining the cost of the process according to the priority of the process; considering the cost of the process when it is running and the external related to the process Factors such as the cost of the job;

(3). Process rollback strategy, that is, let the process participating in the deadlock roll back to a certain point before the deadlock, and continue execution at this point, so that it will not happen again when it is executed again Deadlock. Although this is an ideal method, it is extremely expensive to operate. It is necessary to have a mechanism such as a stack to record every change in the process for future rollbacks. Sometimes this is not possible.

 

 

 

Guess you like

Origin blog.csdn.net/dream_18/article/details/52644903