为何给定Java同步方法代码未发生预期死锁?
为什么这段代码没有发生预期的死锁?
嘿,这个问题抓得特别准!你已经观察到了代码里“看似会互相等待”的场景,但实际没触发死锁,核心原因是Java中synchronized修饰的内置锁是可重入锁。
先拆解代码的执行流程
我们一步步理清楚两个线程的行为:
- 主线程启动后,调用
testClass.func1()——因为func1是synchronized方法,主线程成功获取了TestClass实例的内置锁。 - 主线程在
func1内部调用func2(),虽然func2也是synchronized方法,但当前线程已经持有这把锁了,所以不需要等待,直接进入func2执行(这就是可重入锁的核心特性)。 - 与此同时,
ThreadSample线程启动,调用testClass.func2()——它尝试获取TestClass实例的锁,但这把锁已经被主线程牢牢拿着,所以这个线程会进入阻塞等待状态。 - 主线程在
func2里执行完空循环后,又调用func1()——同样,因为已经持有锁,直接进入递归调用,不会被自己阻塞。
可重入锁的本质
Java的每个内置锁都绑定了两个关键信息:
- 持有该锁的线程
- 一个持有计数
当线程第一次获取锁时,计数设为1;如果同一个线程再次请求这把锁,计数就会加1;每次线程退出synchronized方法/代码块,计数减1,只有当计数回到0时,锁才会被释放,其他线程才有机会获取。
为什么没有死锁?
死锁的形成需要满足四个必要条件:互斥、请求与保持、不剥夺、循环等待。而你的代码里,根本没形成“循环等待”:
- 主线程自始至终持有锁,一直在递归执行
func1→func2→func1的逻辑,它从来没有等待ThreadSample线程持有的任何资源; ThreadSample线程只是单方面等待主线程释放锁,没有反过来让主线程等待它。
说白了,这不是“互相等待”,只是一个线程在等另一个线程释放锁,而持有锁的线程一直在自己递归执行,自然不会触发死锁。
补充:这段代码其实会触发
StackOverflowError,因为主线程一直在递归调用func1和func2,栈帧会不断累积直到超出JVM的栈容量,但这和死锁是完全不同的问题哦。
内容的提问来源于stack exchange,提问作者jack.math
相关产品推荐
相关产品推荐

