0
点赞
收藏
分享

微信扫一扫

死锁的讲解

alanwhy 2022-04-03 阅读 70

目录

1. 死锁定义

2. 死锁产生原因

3. 如何解决死锁问题


1. 死锁定义

死锁是指两个或两个以上的进程在执⾏过程中,由于竞争资源或者由于彼此通信⽽造成的⼀种阻塞的现象,若⽆外⼒作⽤,它们都将⽆法推进下去。(也就是两个线程拥有锁的情况下,⼜在尝试获取对⽅锁,从⽽造成程序⼀直阻塞的情况。)

2. 死锁产生原因

形成死锁主要由以下 4 个因素造成的:

        ① 互斥条件 ⼀个资源只能被⼀个线程占有,当这个资源被占⽤之后其他线程就只能等待。

        ② 不可被剥夺条件 当⼀个线程不主动释放资源时,此资源⼀直被拥有线程占有,其他线程不能得到此资源。

        ③ 请求并持有条件 线程已经拥有了⼀个资源之后,又尝试请求新的资源。

        ④ 环路等待条件 产⽣死锁⼀定是发⽣了线程资源环形链。

形成死锁,四个因素缺一不可。

3. 如何解决死锁问题

打破产生死锁的一个或者多个条件即可。

        ① 互斥条件 改变不了。

        ② 不可被剥夺条件 改变不了。

        ③ 请求并持有条件 可以改变(人为控制)。

        ④ 环路等待条件 可以改变(人为控制)。

public class UnDeadLock {
    public static void main(String[] args) {
        Object lockA = new Object();
        Object lockB = new Object();

        Thread t1 = new Thread(() -> {
            synchronized (lockA) {
                System.out.println("线程1:得到锁A");
                //业务代码
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lockB) {
                    System.out.println("线程1:得到锁B");
                    //业务代码
                    System.out.println("线程1:释放锁B");
                }
                System.out.println("线程1:释放锁A");
            }
        },"线程1");
        t1.start();

        Thread t2 = new Thread(() -> {
            synchronized (lockB) {
                System.out.println("线程2:得到锁B");
                //业务代码
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lockA) {
                    System.out.println("线程2:得到锁A");
                    //业务代码
                    System.out.println("线程2:释放锁A");
                }
                System.out.println("线程2:释放锁A");
            }
        },"线程2");
        t2.start();
    }
}

输出
    线程1:得到锁A
    线程2:得到锁B
(......没有结束)

上面代码产生了死锁。解决方法:

1. 修改获取锁请求并持有条件:

解决死锁方法:破坏请求并持有条件

public class UnDeadLock {
    public static void main(String[] args) {
        Object lockA = new Object();
        Object lockB = new Object();

        Thread t1 = new Thread(() -> {
            synchronized (lockA) {
                System.out.println("线程1:得到锁A");
                //业务代码
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
//                synchronized (lockB) {
//                    System.out.println("线程1:得到锁B");
//                    //业务代码
//                    System.out.println("线程1:释放锁B");
//                }
                System.out.println("线程1:释放锁A");
            }
        },"线程1");
        t1.start();

        Thread t2 = new Thread(() -> {
            synchronized (lockB) {
                System.out.println("线程2:得到锁B");
                //业务代码
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
//                synchronized (lockA) {
//                    System.out.println("线程2:得到锁A");
//                    //业务代码
//                    System.out.println("线程2:释放锁A");
//                }
                System.out.println("线程2:释放锁B");
            }
        },"线程2");
        t2.start();
    }
}

输出:
    线程1:得到锁A
    线程2:得到锁B
    线程2:释放锁B
    线程1:释放锁A

 2. 修改获取锁的有序性来改变环路等待条件:

(使用顺序锁解决死锁问题)

 

 

解决死锁方法:修改获取锁的有序性来改变环路等待条件

public class UnDeadLock2 {
    public static void main(String[] args) {
        Object lockA = new Object();
        Object lockB = new Object();

        Thread t1 = new Thread(() -> {
            synchronized (lockA) {
                System.out.println("线程1:得到锁A");
                //业务代码
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lockB) {
                    System.out.println("线程1:得到锁B");
                    //业务代码
                    System.out.println("线程1:释放锁B");
                }
                System.out.println("线程1:释放锁A");
            }
        },"线程1");
        t1.start();

        Thread t2 = new Thread(() -> {
            synchronized (lockA) {
                System.out.println("线程2:得到锁A");
                //业务代码
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lockB) {
                    System.out.println("线程2:得到锁B");
                    //业务代码
                    System.out.println("线程2:释放锁B");
                }
                System.out.println("线程2:释放锁A");
            }
        },"线程2");
        t2.start();
    }
}

输出:
    线程1:得到锁A
    线程1:得到锁B
    线程1:释放锁B
    线程1:释放锁A
    线程2:得到锁A
    线程2:得到锁B
    线程2:释放锁B
    线程2:释放锁A
举报

相关推荐

0 条评论