偏向锁和轻量级锁

zhidiantech · · 25 次点击 · · 开始浏览    
--- ### 一、设计目标的差异 | **锁类型** | **核心目标** | **适用场景** | |------------|-----------------------------------------------------------------------------|-----------------------------------------------------------------------------| | **偏向锁** | **消除无竞争场景下的同步开销**,通过记录首次获得锁的线程 ID,后续无需任何同步操作 | 单线程重复访问同步代码(如工具类单例初始化) | | **轻量级锁** | **减少轻量竞争场景的互斥量开销**,通过 CAS 自旋避免线程挂起 | 多线程交替访问同步块(如生产者-消费者模型中交替执行) | **关键区别**: 偏向锁直接消除同步操作(包括 CAS),而轻量级锁仍需通过 CAS 操作获取锁,但避免了操作系统级线程阻塞。 --- ### 二、加锁机制的对比 1. **偏向锁的加锁流程** • **初始化**:首次获取锁时,通过 CAS 将线程 ID 写入对象头的 Mark Word • **后续访问**:直接检查线程 ID 是否匹配,无任何同步操作 • **示例**:若线程 A 第一次获取锁后,后续每次进入同步块时仅需验证线程 ID 即可 2. **轻量级锁的加锁流程** • **栈帧分配**:每次进入同步块时,在线程栈中创建锁记录(Lock Record),拷贝 Mark Word • **CAS 竞争**:尝试将对象头指针指向锁记录,若失败则自旋重试(默认 10 次) • **示例**:线程 A 和线程 B 交替执行同步块时,通过 CAS 交替更新锁记录指针 --- ### 三、竞争处理方式的区别 | **竞争场景** | **偏向锁的响应** | **轻量级锁的响应** | |-------------------------|---------------------------------------------------------------------------------|---------------------------------------------------------------------------------| | **首次出现竞争** | 撤销偏向锁,升级为轻量级锁(需暂停原持有偏向锁的线程) | 自旋尝试重新 CAS,失败则膨胀为重量级锁 | | **持续竞争** | 直接升级为重量级锁(无中间状态) | 自旋失败后升级为重量级锁,线程进入阻塞队列 | **典型场景**: • 若线程 A 持有偏向锁时,线程 B 尝试获取锁 → 触发偏向锁撤销,升级为轻量级锁 • 若线程 A 和 B 同时竞争轻量级锁 → 自旋失败后膨胀为重量级锁 --- ### 四、性能与适用性权衡 | **维度** | **偏向锁** | **轻量级锁** | |------------------|---------------------------------------------------------------------------|---------------------------------------------------------------------------| | **无竞争开销** | 零开销(仅首次 CAS) | 每次进入同步块需 CAS 操作 | | **竞争开销** | 高(需暂停线程 + 撤销操作) | 中等(自旋消耗 CPU,但避免线程切换) | | **适用性限制** | 仅适合单线程独占场景,多线程访问时需禁用(-XX:-UseBiasedLocking) | 适合短时间交替竞争场景,长时间竞争会退化为重量级锁 | --- ### 五、线程竞争时的锁状态变化 当 **两个线程同时竞争锁** 时: 1. **偏向锁**:立即失效 → 升级为轻量级锁 → 若仍存在竞争则进一步膨胀为重量级锁 2. **轻量级锁**:自旋重试失败 → 直接膨胀为重量级锁 **结论**: 两者在存在竞争时均会失效,最终依赖重量级锁实现同步,但轻量级锁通过自旋减少了短时间竞争的开销。 --- ### 总结 | **核心差异** | **偏向锁** | **轻量级锁** | |--------------------|------------------------------------|------------------------------------| | **竞争容忍度** | 零容忍(任何竞争都会失效) | 容忍短暂交替竞争 | | **性能优势场景** | 单线程独占同步块 | 多线程交替访问同步块 | | **实现复杂度** | 高(需处理撤销逻辑) | 中(依赖 CAS 自旋) | **选择建议**: • 若代码块 **仅被单线程重复访问**(如工具类初始化),启用偏向锁可最大化性能 • 若存在 **短时间交替竞争**(如任务队列交替执行),轻量级锁更优 • 高竞争场景下两者均需禁用,直接使用 `ConcurrentHashMap` 等并发容器替代同步块
25 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传