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

一文搞懂synchronized实现原理

一、synchronized 内部实现原理(深度结合 Monitor)

1. 核心前提:锁的载体是“对象”

synchronized 无论修饰方法还是代码块,最终都要绑定到一个对象上(实例方法绑定 this,静态方法绑定 Class 对象,代码块绑定自定义对象),而对象的 Monitor(监视器/管程) 是实现锁的核心。

2. Monitor 是什么?

Monitor 是 JVM 层面的一种同步工具,本质是一个对象(C++ 实现),包含以下核心结构:

结构 作用
所有者(Owner) 指向当前持有锁的线程,初始为 null
等待队列(WaitSet) 存放调用 wait() 后进入 WAITING 状态的线程
入口队列(EntryList) 存放竞争锁失败、进入 BLOCKED 状态的线程
重入计数器 记录锁的重入次数(支持可重入),初始为 0,获取锁+1,释放锁-1

3. synchronized 结合 Monitor 的执行流程

graph TDA[线程尝试获取锁] --> B{检查Monitor的Owner};B -->|Owner=null| C[将Owner设为当前线程,重入计数器+1];B -->|Owner=当前线程| D[重入计数器+1(可重入)];B -->|Owner=其他线程| E[线程进入EntryList,变为BLOCKED状态];C --> F[执行临界区代码];D --> F;F --> G{释放锁};G --> H[重入计数器-1];H -->|计数器=0| I[将Owner设为null,唤醒EntryList中一个线程];H -->|计数器>0| J[继续持有锁,线程执行后续代码];I --> K[被唤醒的线程重新竞争锁];

关键细节

  • 可重入性:同一线程多次获取同一把锁,仅增加重入计数器,不会死锁(如同步方法调用另一个同步方法);
  • 释放时机:正常执行完临界区代码/抛出异常时,都会释放锁(JVM 保证 monitorexit 一定会执行);
  • 锁升级与 Monitor
    • 偏向锁/轻量级锁阶段:不依赖完整的 Monitor,仅通过对象头的 Mark Word + CAS 实现,减少开销;
    • 升级为重量级锁后:才会关联到完整的 Monitor,此时竞争失败的线程会进入 EntryList 阻塞。

4. synchronized 的底层指令(代码块 vs 方法)

使用形式 底层实现 Monitor 交互方式
同步代码块 monitorenter / monitorexit 指令 执行 monitorenter 获取 Monitor,monitorexit 释放
同步实例方法 ACC_SYNCHRONIZED 标志位 JVM 自动为 this 对象获取/释放 Monitor
同步静态方法 ACC_SYNCHRONIZED 标志位 JVM 自动为 Class 对象获取/释放 Monitor

二、synchronized vs ReentrantLock 核心区别

ReentrantLockjava.util.concurrent.locks 包下的显式锁,与 synchronized(隐式锁)的核心区别如下,用表格对比更清晰:

对比维度 synchronized ReentrantLock
锁的性质 隐式锁(JVM 层面),自动获取/释放 显式锁(API 层面),需手动 lock()/unlock()(建议放 finally)
可重入性 支持(JVM 自动维护重入计数器) 支持(手动维护,默认非公平锁,可指定公平锁)
公平性 非公平锁(无法修改) 支持公平锁/非公平锁(构造方法指定 new ReentrantLock(true)
锁等待中断 不支持(等待的线程无法被中断) 支持(lockInterruptibly() 可中断等待的线程)
超时获取锁 不支持(线程会一直阻塞) 支持(tryLock(long timeout, TimeUnit) 超时放弃)
条件变量(Condition) 仅支持一个(Object 的 wait/notify) 支持多个(newCondition() 创建多个 Condition,精准唤醒线程)
性能 JDK 1.6 后优化(锁升级),与 ReentrantLock 接近 高并发下略优(灵活控制),但需手动释放
异常处理 自动释放锁(即使抛异常) 需在 finally 中释放,否则会死锁
使用复杂度 简单(无需手动管理) 复杂(需手动控制,易出错)

关键区别的代码示例

1. ReentrantLock 基本使用(显式锁)
import java.util.concurrent.locks.ReentrantLock;public class ReentrantLockDemo {private static final ReentrantLock lock = new ReentrantLock(true); // 公平锁public static void doTask() {lock.lock(); // 手动获取锁try {System.out.println("线程 " + Thread.currentThread().getName() + " 执行任务");Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock(); // 必须在finally中释放,避免死锁}}public static void main(String[] args) {new Thread(ReentrantLockDemo::doTask, "线程1").start();new Thread(ReentrantLockDemo::doTask, "线程2").start();}
}
2. ReentrantLock 中断等待 + 超时获取
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;public class ReentrantLockAdvance {private static final ReentrantLock lock = new ReentrantLock();public static void tryLockWithTimeout() {try {// 超时获取锁:3秒内获取不到则放弃if (lock.tryLock(3, TimeUnit.SECONDS)) {try {System.out.println(Thread.currentThread().getName() + " 获取锁成功");Thread.sleep(5000); // 模拟长时间执行业务} finally {lock.unlock();}} else {System.out.println(Thread.currentThread().getName() + " 超时未获取锁");}} catch (InterruptedException e) {System.out.println(Thread.currentThread().getName() + " 等待锁时被中断");Thread.currentThread().interrupt(); // 恢复中断标记}}public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(ReentrantLockAdvance::tryLockWithTimeout, "线程A");Thread t2 = new Thread(ReentrantLockAdvance::tryLockWithTimeout, "线程B");t1.start();Thread.sleep(1000);t2.start();t2.interrupt(); // 中断线程B的等待}
}

输出结果

线程A 获取锁成功
线程B 等待锁时被中断
线程A 释放锁

三、使用场景选择建议

  1. 优先用 synchronized:大部分场景下(简单同步、低并发),synchronized 足够用,且 JVM 自动优化,无需手动管理,出错概率低;
  2. 选 ReentrantLock 的场景
    • 需要公平锁;
    • 需要中断等待锁的线程、超时获取锁;
    • 需要多个条件变量(精准唤醒部分线程);
    • 高并发场景下需要更灵活的锁控制。

总结

  1. synchronized 基于 JVM 层面的 Monitor 实现,通过对象头的锁状态+锁升级机制保证性能,是隐式锁,自动获取/释放;
  2. ReentrantLock 是 API 层面的显式锁,需手动 lock()/unlock(),支持公平锁、中断等待、超时获取等高级特性;
  3. 选型原则:简单场景用 synchronized,复杂并发场景(需高级特性)用 ReentrantLock,且使用 ReentrantLock 时必须在 finally 中释放锁。
http://www.jsqmd.com/news/440352/

相关文章:

  • Flutter 三方库 drivers_license_parser 的鸿蒙化适配指南 - 掌控 AAMVA 驾照精密解析、身份认证实战、鸿蒙级精密识别专家
  • 2026年 不锈钢管厂家推荐排行榜,304/316L/2205等不锈钢无缝管、卫生级不锈钢管,实力品牌深度解析与选购指南 - 品牌企业推荐师(官方)
  • 2026年高校论文AI率要求越来越严:政策解读与应对方案 - 还在做实验的师兄
  • 为什么你的论文AI率怎么都降不下来?深度分析3个原因 - 还在做实验的师兄
  • Flutter 三方库 jenny 的鸿蒙化适配指南 - 掌控 Yarn Spinner 剧情分支、互动脚本实战、鸿蒙级精密叙事专家
  • 645645
  • 软件: Keil esp固件烧写软件 华为云服务器(个人免费使用,每天消息上限) 二、调试过程 调试总体思路: 烧写官方的MQTT固 ...
  • 嘎嘎降AI和比话降AI怎么选?不同预算不同选择 - 还在做实验的师兄
  • 2026年 混合机厂家推荐排行榜:螺带/卧式/双动力/单锥/VC/高速/双行星/V型/双锥/无重力/犁刀/连续式混合机,高效混合技术实力品牌深度解析 - 品牌企业推荐师(官方)
  • pnpm . 支持JavaScript运行时的安装了
  • 嘎嘎降AI vs 笔灵降AI vs 零感AI:三款热门工具横评实测 - 还在做实验的师兄
  • [深度学习] 大模型学习-RAG技术全景解析
  • 论文降AI完整流程:从检测到修改再到复查,一篇搞定 - 还在做实验的师兄
  • 2026年四川电力资质代办厂家推荐榜单:电力安装/试验/总包/运维/施工/调试/检修/输变电/承装修试许可证一站式办理指南 - 品牌企业推荐师(官方)
  • MATLAB代码:基于分布式ADMM算法的考虑碳排放交易的电力系统优化调度研究 关键词
  • 一步一步学习使用LiveBindings() 实现对JSON数据的绑定
  • AIGC检测到底是怎么检测的?搞懂原理才能有效降AI - 还在做实验的师兄
  • 2026最新|如何联系探潜数据分析?业务介绍+官方渠道汇总 - 速递信息
  • AI应用运维人力成本高?架构师的3个AI运维+自动化方案
  • 降AI工具大PK:嘎嘎降AI、去AIGC、率零谁更能打? - 还在做实验的师兄
  • 【毕设】基于Spring Boot的宠物咖啡馆平台的设计与实现
  • 知网AIGC检测不通过怎么办?过来人的实用补救攻略 - 还在做实验的师兄
  • EtherCAT总线轴控制与机器人组合的创新检测应用,附详细注释与前沿技术的实践实践参考程序
  • 数据编排在AI_ML大数据流水线中的应用实践
  • 2026年沈阳24小时上门换锁芯便民服务机构哪家好?居家换锁芯、汽车换锁芯、智能锁安装、锁具维修、配汽车钥匙 - 海棠依旧大
  • 2026年GEO优化实操手册:手把手打造品牌AI搜索可见性
  • 第 2 章 企业级 AI Agent 平台核心概念与理论基础 ~ 第 6 章 系统 API 设计与接口规范 /《面向企业级 AI Agent 自动化智能体开发和应用平台原理与开发实践》
  • 西门子1500PLC博途V16程序与Wincc7.5画面:水处理滤液生化段处理项目案例
  • 2026年昆山代理记账服务商推荐榜:专业代理记账报税,覆盖小规模、一般纳税人、合规、外资及内资企业一站式财税解决方案 - 品牌企业推荐师(官方)
  • 2026年奥迪原厂升级深度推荐榜单:原厂配置升级/改装/加装,涵盖座椅加热、方向盘加热及内饰专修,专业品质与匠心服务之选 - 品牌企业推荐师(官方)