Detailed explanation of java deadlock problem

1. What is a deadlock

Deadlocks are uncommon not only in personal learning, but even in development. But once a deadlock occurs, the consequences will be very serious.
First of all, what is a deadlock? To use an analogy, it’s as if two people are fighting, restraining each other (locking, embracing) each other, unable to move each other, and being arrogant to each other, if you don’t let go, I won’t let go. Well, no one can move.
In a multi-threaded environment, resources are bound to be robbed. When two threads lock the current resources, but both need the other's resources to proceed to the next step, the two parties will always wait for the other's resources to be released. This forms a deadlock. These processes that are forever waiting for each other are called deadlocked processes.

So let's summarize the conditions for deadlock generation:

1. 互斥:资源的锁是排他性的,加锁期间只能有一个线程拥有该资源。其他线程只能等待锁释放才能尝试获取该资源。
2. 请求和保持:当前线程已经拥有至少一个资源,但其同时又发出新的资源请求,而被请求的资源被其他线程拥有。此时进入保持当前资源并等待下个资源的状态。
3. 不剥夺:线程已拥有的资源,只能由自己释放,不能被其他线程剥夺。
4. 循环等待:是指有多个线程互相的请求对方的资源,但同时拥有对方下一步所需的资源。形成一种循环,类似2)请求和保持。但此处指多个线程的关系。并不是指单个线程一直在循环中等待。

What? Still don't understand? Then we go directly to the code and write a deadlock by hand.

2. Write deadlock by hand

Depending on the condition, we let the two threads request hold from each other.

public class DeadLockDemo implements Runnable{
    
    

    public static int flag = 1;

    //static 变量是 类对象共享的
    static Object o1 = new Object();
    static Object o2 = new Object();

    @Override
    public void run() {
    
    
        System.out.println(Thread.currentThread().getName() + ":此时 flag = " + flag);
        if(flag == 1){
    
    
            synchronized (o1){
    
    
                try {
    
    
                    System.out.println("我是" + Thread.currentThread().getName() + "锁住 o1");
                    Thread.sleep(3000);
                    System.out.println(Thread.currentThread().getName() + "醒来->准备获取 o2");
                }catch (Exception e){
    
    
                    e.printStackTrace();
                }
                synchronized (o2){
    
    
                    System.out.println(Thread.currentThread().getName() + "拿到 o2");//第24行
                }
            }
        }
        if(flag == 0){
    
    
            synchronized (o2){
    
    
                try {
    
    
                    System.out.println("我是" + Thread.currentThread().getName() + "锁住 o2");
                    Thread.sleep(3000);
                    System.out.println(Thread.currentThread().getName() + "醒来->准备获取 o2");
                }catch (Exception e){
    
    
                    e.printStackTrace();
                }
                synchronized (o1){
    
    
                    System.out.println(Thread.currentThread().getName() + "拿到 o1");//第38行
                }
            }
        }
    }

    public static  void main(String args[]){
    
    

        DeadLockDemo t1 = new DeadLockDemo();
        DeadLockDemo t2 = new DeadLockDemo();
        t1.flag = 1;
        new Thread(t1).start();

        //让main线程休眠1秒钟,保证t2开启锁住o2.进入死锁
        try {
    
    
            Thread.sleep(1000);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }

        t2.flag = 0;
        new Thread(t2).start();

    }
}

In the code,
t1 is created, t1 gets the lock of o1 first, and starts to sleep for 3 seconds. Then
the t2 thread is created, t2 gets the lock of o2, and starts to sleep for 3 seconds. Then
t1 wakes up first, ready to take the lock of o2, and finds that o2 has been locked, and can only wait for the lock of o2 to be released.
Wake up after t2, ready to take the lock of o1, and find that o1 has been locked, and can only wait for the lock of o1 to be released.
t1, t2 form a deadlock.

We check the running status,
insert image description here

3. Find and check the deadlock situation

We use the tools provided by jdk to locate the deadlock problem:

1. jps显示所有当前Java虚拟机进程名及pid.
2. jstack打印进程堆栈信息。

insert image description here

List all java processes.
Let's check DeadLockDemo, why this thread does not unwind the stack.

jstack 11170

insert image description here

Let's go straight to the end: a java-level deadlock has been detected. Two of the threads are stuck on lines 38 and 24 of the code, respectively. Check the corresponding location of our code to troubleshoot errors. Here we can never get the second lock, so it is deadlocked.

insert image description here

Four, the solution

Once a deadlock occurs, we cannot resolve it. So we can only avoid the occurrence of deadlock.
Since deadlock needs to meet four conditions, then we start with the conditions, as long as we break any rules.

1. (互斥)尽量少用互斥锁,能加读锁,不加写锁。当然这条无法避免。
2. (请求和保持)采用资源静态分配策略(进程资源静态分配方式是指一个进程在建立时就分配了它需要的全部资源).我们尽量不让线程同时去请求多个锁,或者在拥有一个锁又请求不到下个锁时,不保持等待,先释放资源等待一段时间在重新请求。
3. (不剥夺)允许进程剥夺使用其他进程占有的资源。优先级。
4. (循环等待)尽量调整获得锁的顺序,不发生嵌套资源请求。加入超时。

Guess you like

Origin blog.csdn.net/zy_dreamer/article/details/132364470