【Java】死锁

死锁说白了,就是在程序中出现了锁的嵌套。

image-20240506202045038

死锁不是一个知识点,它是一个错误。

现在我们学习死锁的目的就是:以后不要犯这个错误。

A线程拿着A锁,B线程拿着B锁,它们都在等着对方释放锁,此时程序就会卡死,运行不下去。

由于死锁不是一个知识点,而是一个错误,因此下面的代码是不需要你去练的,你只需要理解它的过程就行了

测试类

yThread t1 = new MyThread();
MyThread t2 = new MyThread();

t1.setName("线程A");
t2.setName("线程B");

t1.start();
t2.start();

MyThread.java

public class MyThread extends Thread {
    //定义了两把锁,一把A锁一把B锁
    static Object objA = new Object();
    static Object objB = new Object();

    @Override
    public void run() {
        //1.循环
        while (true) {
            //如果是线程A就执行这段
            if ("线程A".equals(getName())) {
                //先是A锁
                synchronized (objA) {
                    System.out.println("线程A拿到了A锁,准备拿B锁");//A
                    //再是B锁
                    synchronized (objB) {
                        System.out.println("线程A拿到了B锁,顺利执行完一轮");
                    }
                }
            } else if ("线程B".equals(getName())) { //如果是线程B,就执行这段
                if ("线程B".equals(getName())) {
                    //但是在线程B中,先是B锁
                    synchronized (objB) {
                        System.out.println("线程B拿到了B锁,准备拿A锁");//B
                        //再是A锁
                        synchronized (objA) {
                            System.out.println("线程B拿到了A锁,顺利执行完一轮");
                        }
                    }
                }
            }
        }
    }
}

此时它会出现什么情况呢?运行程序发现,程序卡死了。

image-20240506202805365

那为什么会开始呢?

首先还是线程A、线程B在抢夺CPU的执行权

@Override
public void run() { //A //B
    ....
}

假设现在是线程A抢到了,此时它就会进去,然后做一个判断,是线程A就会执行线程A里面的代码

在执行的时候默认情况下锁都是打开的,所以A可以拿到 objA,即A锁

@Override
public void run() {
    while (true) {
        if ("线程A".equals(getName())) {
            synchronized (objA) { //拿到A锁
                //一旦拿到后,A锁就关闭了
                System.out.println("线程A拿到了A锁,准备拿B锁");//然后打印这句话
                //但是当线程A还没有拿到B锁,此时CPU的执行权被上面的线程B抢到了
                synchronized (objB) {
                    System.out.println("线程A拿到了B锁,顺利执行完一轮");
                }
            }
        } else if ("线程B".equals(getName())) {
            //线程B就会执行到这段代码,此时B锁是打开的,因为线程A停在了第7行,它导致了A锁关闭,但是它还没去操作B锁
            synchronized (objB) { //因此此时线程B在执行的时候,看到B锁,是可以进来的
                System.out.println("线程B拿到了B锁,准备拿A锁");//进来后就会打印这句话
                //但是此时就出问题了,B如果想要继续往下执行,就必须要让A锁打开
                //但是A锁打开不了,因为线程A还在拿着A锁
                //那A锁什么时候才能释放呢?很简单,只有当synchronized (objA) 代码块中所有代码都执行完了,A锁才能释放。
                //说白了线程A需要拿到B锁然后执行完里面的代码A锁才能释放
                //但是线程A进不去,因为B锁已经被线程B拿到了
                synchronized (objA) {
                    System.out.println("线程B拿到了A锁,顺利执行完一轮");
                }
            }
        }
    }
}

此时线程A正在等着线程B释放锁,而线程B又在等着线程A释放锁,此时两个线程都会卡死在对应的地方:A线程卡死在第7行,B线程卡死在16行,这个时候程序就运行不下去了,这个就是死锁

总结:以后我们在写锁的时候,千万不要让两个锁嵌套就行了。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值