synchronized 可重入机制

一、一句话核心

同一个线程可以多次获取同一把锁,不会死锁。

  • 原理:锁自带计数器,加锁+1,释放-1,归0才真正释放
  • 类比:一把家门钥匙能开家里所有房间门

二、为什么必须有可重入?

没有可重入,下面代码会直接死锁

public synchronized void a() { b(); } // 拿了锁调用b()
public synchronized void b() {}       // 再拿同一把锁,自己等自己

三、三种锁的可重入实现对比

锁状态 计数器在哪 怎么判断是同一个线程
偏向锁 对象头Mark Word 检查里面存的线程ID
轻量级锁 线程栈的Lock Record链表 检查锁记录的所有者
重量级锁 Monitor对象的count字段 检查Monitor的owner

四、重量级锁(最常考)实现

Monitor核心结构

Monitor

owner: 谁拿着锁

count: 重入次数

执行流程

线程拿锁

owner是自己?

count+1

owner是空?

owner=自己, count=1

排队等

执行代码

释放: count-1

count=0?

owner清空, 唤醒排队线程

锁还在自己手里

五、轻量级锁实现

栈里多个锁记录代替计数器:

线程栈

锁记录3

锁记录2

锁记录1 ← 对象头指向这里

  • 重入1次,栈里多1个锁记录
  • 释放1次,栈里弹出1个锁记录
  • 全弹完,锁真正释放

六、常见误区

误区 正确结论
不同线程也能重入 只允许同一个线程
静态和普通方法能互相重入 锁的对象不同,不能
重入次数无限 最多2^31-1次,超了报错

七、关键总结

特性 说明
核心目的 避免自己把自己卡死
性能影响 几乎为0,只是计数器加减
释放规则 加锁多少次,必须释放多少次

更多推荐