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启动,调用
alphonse.bow(gaston):因为bow是同步方法,线程1先抢到了阿方斯对象的钥匙,然后执行打印语句,接下来要调用gaston.bowBack(this)——这时候需要加斯顿对象的钥匙。 - 几乎同时,线程2启动,调用
gaston.bow(alphonse):同样,线程2抢到了加斯顿对象的钥匙,执行打印语句后,要调用alphonse.bowBack(this)——需要阿方斯对象的钥匙。 - 现在尴尬了:线程1拿着阿方斯的钥匙,等着加斯顿的钥匙;线程2拿着加斯顿的钥匙,等着阿方斯的钥匙。俩线程都不肯先放下自己手里的钥匙,就这么僵死在那儿了!
bowBack自然永远没机会执行。
为啥不加synchronized就正常?
没加同步关键字的话,方法就不需要抢“钥匙”,两个线程可以随便调用对方的方法,不会互相卡住,程序该干啥干啥,自然能正常跑完。
一句话总结死锁的核心
两个线程互相持有对方必须的资源(锁),且都不肯释放自己的资源,导致彼此都无法继续执行——这就是死锁的本质。
内容的提问来源于stack exchange,提问作者k13i




