You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Java中同步方法引发死锁问题咨询

为啥同步方法会引发死锁?通俗拆解来啦!

嘿,这个坑我当初学Java并发的时候也踩过!咱们用你说的Oracle教程里的经典场景来唠明白~

先还原你的代码场景(大概率是这样的)

先贴一下典型的死锁代码片段(应该和你写的差不多):

class Friend {
    private final String name;

    public Friend(String name) {
        this.name = name;
    }

    public String getName() {
        return this.name;
    }

    // 同步的bow方法
    public synchronized void bow(Friend bower) {
        System.out.printf("%s: %s 向我鞠躬了!%n", this.name, bower.getName());
        // 调用对方的bowBack
        bower.bowBack(this);
    }

    // 同步的bowBack方法
    public synchronized void bowBack(Friend bower) {
        System.out.printf("%s: %s 向我回礼了!%n", this.name, bower.getName());
    }
}

public class DeadlockDemo {
    public static void main(String[] args) {
        final Friend alphonse = new Friend("阿方斯");
        final Friend gaston = new Friend("加斯顿");

        // 线程1:阿方斯向加斯顿鞠躬
        new Thread(() -> alphonse.bow(gaston)).start();
        // 线程2:加斯顿向阿方斯鞠躬
        new Thread(() -> gaston.bow(alphonse)).start();
    }
}

死锁到底是怎么发生的?用大白话讲

咱们把锁比作家门钥匙,同步方法的本质就是:调用方法前必须先拿到这个对象的“钥匙”,没钥匙就只能等着。

  1. 线程1启动,调用alphonse.bow(gaston):因为bow是同步方法,线程1先抢到了阿方斯对象的钥匙,然后执行打印语句,接下来要调用gaston.bowBack(this)——这时候需要加斯顿对象的钥匙
  2. 几乎同时,线程2启动,调用gaston.bow(alphonse):同样,线程2抢到了加斯顿对象的钥匙,执行打印语句后,要调用alphonse.bowBack(this)——需要阿方斯对象的钥匙
  3. 现在尴尬了:线程1拿着阿方斯的钥匙,等着加斯顿的钥匙;线程2拿着加斯顿的钥匙,等着阿方斯的钥匙。俩线程都不肯先放下自己手里的钥匙,就这么僵死在那儿了!bowBack自然永远没机会执行。

为啥不加synchronized就正常?

没加同步关键字的话,方法就不需要抢“钥匙”,两个线程可以随便调用对方的方法,不会互相卡住,程序该干啥干啥,自然能正常跑完。

一句话总结死锁的核心

两个线程互相持有对方必须的资源(锁),且都不肯释放自己的资源,导致彼此都无法继续执行——这就是死锁的本质。

内容的提问来源于stack exchange,提问作者k13i

火山引擎 最新活动