请谈谈你对死锁的理解?

多线程和锁

多线程和锁作为并发编程的两个重要概念,在提升了程序性能的同时,也带来了一些编码的复杂性。锁的出现就是为了保证在多线程的时候操作一组资源数据的一致性,我们在给资源加上锁之后,只有拥有了这个锁的线程才能操作此资源,其余的线程只能排队。

举个例子:例如你去换衣间试衣服,你进去了把门锁上,那么在这期间谁都无法进入,等你开门出来,别人才能进入。

什么是死锁

死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。(百度百科)

通俗点说:死锁就是两个线程同时占用两个资源,但又在彼此等待对方释放锁
在这里插入图片描述

模拟死锁

public class Test {
    public static final Object lock1 = new Object();
    public static final Object lock2 = new Object();

    public static void main(String[] args) {
        /*模拟死锁*/
        deadLock();
    }

    /***
     * 模拟死锁
     */
    public static void deadLock() {
        /*线程1拥有lock1之后试图获取lock2*/
        Thread thread1 = new Thread(() -> {
            while (true) {
                synchronized (Test.lock1) {
                    System.out.println("线程1:" + Thread.currentThread().getName() + " 执行成功");
                    try {
                        Thread.sleep(1000);
                        synchronized (Test.lock2) {
                            System.out.println(Thread.currentThread().getName());
                            Thread.sleep(1000);
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        /*线程2拥有lock2之后试图获取lock1*/
        Thread thread2 = new Thread(() -> {
            while (true) {
                synchronized (Test.lock2) {
                    System.out.println("线程2:" + Thread.currentThread().getName()+ " 执行成功");
                    try {
                        Thread.sleep(1000);
                        synchronized (Test.lock1) {
                            System.out.println(Thread.currentThread().getName());
                            Thread.sleep(1000);
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        thread1.start();
        thread2.start();
    }


}

执行

线程1:Thread-0 执行成功
线程2:Thread-1 执行成功


到这里发现程序不在往下执行,卡在了这个瞬间。
因为我们使用线程1拥有锁lock1的同时试图获取lock2,在线程2拥有锁lock2的同时试图获取lock1,这样就会造成彼此都在等待对方释放锁资源,这样就形成了死锁

避免死锁

死锁发生的条件为

  • 互斥,共享资源X和Y只能被一个线程占用
  • 占有且等待,线程T1已经取得共享资源X,在等待共享资源Y的时候,不释放共享资源X
  • 不可抢占,其他线程不能强行抢占线程T1占用的资源
  • 循环等待,线程1等待线程2占用的资源,线程2等待线程1占有的资源,就是循环等待

预防死锁的策略

  1. 破坏占用且等待条件,可以一次性申请所有资源
  2. 破坏不可抢占条件
  3. 破坏循环等待条件,对资源进行排序,按序申请资源

例如上述代码例子,我们如何修改能避免死锁的产生呢?
我们只需要让thread1和thread2获取lock1和lock2的顺序相同即可.
代码如下:


public class Test {
    public static final Object lock1 = new Object();
    public static final Object lock2 = new Object();

    public static void main(String[] args) {
        /*模拟死锁*/
        deadLock();
    }

    /***
     * 模拟死锁
     */
    public static void deadLock() {
        /*线程1拥有lock1之后试图获取lock2*/
        Thread thread1 = new Thread(() -> {
            while (true) {
                synchronized (Test.lock1) {
                    System.out.println("线程1:" + Thread.currentThread().getName() + " 执行成功");
                    try {
                        Thread.sleep(1000);
                        synchronized (Test.lock2) {
                            System.out.println(Thread.currentThread().getName());
                            Thread.sleep(1000);
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        /*线程2拥有lock1之后试图获取lock2*/
        Thread thread2 = new Thread(() -> {
            while (true) {
                synchronized (Test.lock1) {
                    System.out.println("线程2:" + Thread.currentThread().getName()+ " 执行成功");
                    try {
                        Thread.sleep(1000);
                        synchronized (Test.lock2) {
                            System.out.println(Thread.currentThread().getName());
                            Thread.sleep(1000);
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        thread1.start();
        thread2.start();
    }


}

猜你喜欢

转载自blog.csdn.net/qq_35416214/article/details/107143615