当前位置: 首页 > news >正文

synchronized 底层实现原理


用快递驿站寄存柜类比synchronized锁机制

想象你有一个24小时快递驿站,寄存柜就是Java对象,每个寄存柜都有智能锁(对象头里的锁标记),不同使用场景对应不同锁策略:


一、基础操作流程

  1. 顾客取件(线程访问)
    • 走到寄存柜前(进入同步代码块)
    • 尝试开锁(通过对象头判断锁状态)
    • 成功:放入/取出快递(执行代码)
    • 失败:根据情况选择等待方式(锁升级)

二、锁状态升级详解(寄存柜智能锁策略)

1. 偏向锁模式(VIP顾客专属)
  • 场景:经常只有老王一个人来取快递
  • 操作
    • 第一次开锁:登记老王指纹(CAS记录线程ID到对象头)
    • 后续开锁:直接指纹验证通过(无需额外操作)
  • 优势:零额外开销
    // 对象头存储结构示例
    | 锁状态 | 线程ID | epoch | 其他 |
    | 偏向锁 | 老王   | 001   | ... |
    
2. 轻量级锁(临时借用密码纸)
  • 场景:偶尔有小张和老王交替取件(无实际竞争)
  • 操作
    1. 生成一次性密码(将对象头复制到线程栈)
    2. 尝试用密码纸开锁(CAS替换对象头为指向栈的指针)
    3. 成功:5秒内自动失效(自旋计数)
    4. 失败:升级为人工柜台处理(重量级锁)
  • 优势:避免叫醒管理员(避免OS线程切换)
    // 栈中存储的锁记录(Lock Record)
    class LockRecord {
        Object displacedMark; // 原始对象头拷贝
        Object owner;         // 指向当前对象
    }
    
3. 重量级锁(人工柜台排队)
  • 场景:双11高峰期多人同时取件(高竞争)
  • 操作
    • 触发警报唤醒管理员(OS内核介入)
    • 取号机发放排队号码(EntryList维护阻塞队列)
    • 叫号后凭号码开柜(线程被唤醒后获取锁)
  • 代价:需要支付人工费(系统调用开销大)
    // 对象头指向操作系统级互斥量(mutex)
    | 锁状态      | 互斥量指针          |
    | 重量级锁 | 0x789abc (指向mutex) |
    

三、底层实现关键步骤

1. monitorenter指令执行流程
// 伪代码演示锁获取过程
if (对象处于无锁状态) {
    if (允许偏向锁 && 当前线程已登记) {
        直接进入同步块; // 偏向锁生效
    } else {
        尝试轻量级锁CAS操作;
        if (成功) 进入同步块;
        else 升级锁状态;
    }
} else {
    if (当前线程已持有锁) {
        锁计数器+1; // 可重入实现
    } else {
        加入等待队列;
        挂起线程; // 重量级锁阻塞
    }
}
2. 内存屏障保障(可见性)
  • 写入屏障:退出同步块时强制刷新变量到主内存
  • 读取屏障:进入同步块时从主内存加载最新值
// 相当于在同步块前后自动添加:
synchronized(obj) {
    MemoryBarrier(); // 内存屏障
    // 业务代码
    MemoryBarrier();
}

四、高频面试扩展点

1. 锁膨胀过程
首次加锁
其他线程访问
自旋失败
释放后
无锁
偏向锁
轻量级锁
重量级锁
2. 锁消除案例
// JIT编译器发现局部StringBuffer不可能被共享
public String createString() {
    StringBuffer sb = new StringBuffer();
    synchronized(sb) { // 这个锁会被消除
        sb.append("hello");
    }
    return sb.toString();
}
3. 锁粗化优化
// 连续多次加锁合并为一次
for (int i=0; i<100; i++) {
    synchronized(obj) { // 合并到循环外部
        doSomething();
    }
}

总结记忆卡
synchronized底层是智能锁升级系统:

  1. 单人用→偏向锁(VIP快速通道)
  2. 交替用→轻量锁(密码纸自助)
  3. 抢着用→重量锁(人工柜台排队)
    配合内存屏障保障可见性,通过锁消除/粗化提升性能,实现高效线程安全。

相关文章:

  • 【Java项目】基于Spring Boot的体质测试数据分析及可视化设计
  • 学习笔记05——HashMap实现原理及源码解析(JDK8)
  • vscode java环境中文乱码的问题
  • 本地AI可视化集成工具-开源的AnythingLLM
  • 每日一题——两数之和
  • OpenHarmony DFX子系统
  • 【组态PLC】基于三菱西门子S7-200PLC和组态王液料混合系统组态设计【含PLC组态源码 M016期】
  • DeepSeek R1满血+火山引擎详细教程
  • PyTorch 源码学习:GPU 内存管理之深入分析 CUDACachingAllocator
  • PINN求解固体力学问题——论文加代码
  • php 对接mqtt 完整版本,订阅消息,发送消息
  • vue实现根据点击或滑动展示对应高亮
  • 【Rust中级教程】2.10. API设计原则之受约束性(constrained) Pt.1:对类型进行修改、`#[non_exhaustive]`注解
  • QT中的事件
  • 基于Java+SpringBoot+Vue的前后端分离的租房网站
  • Shell基础
  • 2011-2019年各省人口数数据
  • vue3动态引入图片
  • 前端依赖nrm镜像管理工具
  • 软考程序员考试内容和备考策略
  • 建设银行南昌分行引金融“活水”,精准灌溉乡村沃土
  • 国台办:提醒相关人员不要假借去第三地名义绕道赴台
  • 济南高新区一季度GDP增长8.5%,第二产业增加值同比增长14.4%
  • 事关广大农民利益,农村集体经济组织法5月1日起施行
  • 游客曝九寨沟打网约车被出租车围堵,官方:前者违规,后者做法不对
  • 路边“僵尸车”被人以1450元卖了,嫌疑人被刑拘