前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【高薪程序员必看】万字长文拆解Java并发编程!(4-1):悲观锁底层原理与性能优化实战

【高薪程序员必看】万字长文拆解Java并发编程!(4-1):悲观锁底层原理与性能优化实战

作者头像
摘星.
发布于 2025-05-20 06:25:36
发布于 2025-05-20 06:25:36
780
举报
文章被收录于专栏:博客专享博客专享
Hello大家好!👋 我是摘星✨,今天我们来深度拆解Java并发编程中最经典的​「悲观锁」🔒设计。

在多线程环境下,当你的转账操作被重复提交💸、库存被超卖📉、计数器结果离奇错误❌时,背后往往是因为缺乏合理的锁控制。而悲观锁作为Java并发中最「简单粗暴」的解决方案,从JDK1.0时代的重量级锁⛓️,到如今JVM层级的锁升级优化⚡,其底层实现堪称一部高性能并发的发展史📜

本文将带你穿透**synchronized关键字**的表面语法,直击三大核心问题💡:

  1. ​**🤔 为什么悲观锁能保证线程安全?**​(从Java对象头到Monitor的硬件级协作)
  2. ​**⚡ JDK1.6后synchronized如何实现性能飞跃?**​(偏向锁/轻量级锁的取舍智慧)
  3. ​**🚫 高并发场景下如何规避锁的性能陷阱?**​(从字节码层面理解锁膨胀的条件)

📌 举个真实案例:某电商平台在秒杀活动中使用synchronized导致TPS从8000📈暴跌到300📉,最终通过缩小锁粒度+锁分离优化提升15倍性能🚀——我们将在文中用代码还原这个优化过程。

下面我们直接切入正题,从操作系统与JVM的协作契约🤝开始讲起!

4. 有锁并发-悲观锁

4.1. 悲观锁思想

悲观锁:假设其他线程会修改共享资源,在进入同步代码块时就加上锁,防止其他线程的干扰。但是如果竞争激烈,就会发生线程上下文切换,性能相对低。

4.2. Synchronized

synchronized关键字,基于Monitor实现,用于实现多线程之间的同步,是悲观锁

synchronized的执行流程:

  1. 第一个线程获取对象锁执行同步代码块
  2. 其他想要获取对象锁进入同步代码块的线程进入阻塞状态
  3. 第一个线程退出同步代码块释放锁后,会唤醒阻塞中的线程
  4. 被唤醒的线程进行非公平的锁争抢,抢到锁的线程执行同步代码块,其他线程继续阻塞

synchronized的特性:

  1. 原子性(Atomicity):synchronized保证同时只能有一个线程执行同步代码块,对共享数据的操作是原子的。
  2. 可见性(Visibility):一个线程执行synchronized同步代码块时,会先获取主内存中的数据到工作内存中,修改共享资源,退出同步代码块时,会将工作内存中的数据刷新到主内存中,保证数据的可见性。
  3. 有序性(Ordering):synchronized会禁止JVM对字节码指令重排优化,保证线程执行的有序性。

synchronized的作用范围:

  1. 成员方法:synchronized修饰成员方法时,锁住的是当前对象实例。
  2. 静态方法:synchronized修饰静态方法时,锁定的是当前类的Class对象。
  3. 代码块:synchronized修饰代码块时,锁定的是指定的对象。

多线程只有获取同一个对象的锁才能起到同步互斥的效果

JDK1.6之前synchronized是重量级锁,jdk1.6之后对synchronized做了一系列优化,加入了偏向锁和轻量级锁,优化了线程上下文切换的性能

4.3. Java对象头

synchronized是悲观锁,在操作共享资源之前需要先加锁,加的锁就存在于Java对象头中.

Hotspot虚拟机中的对象头主要包含两部分数据:Mark Word(标记字段)和Klass Pointer(类型指针)

  • Mark Word:存储对象的hashcode,分代年龄,锁标志位信息.这些信息跟对象自定定义无关,所以Mark Word被设计为非固定的数据结构以便在极小的空间中存储多的数据,它会根据对象的状态复用空间,也就是说在运行期间,Mark Word中的存储数据会跟着锁标志位变化而变化
  • Klass Pointer:指向类元数据的指针,用于确定当前对象是哪个类的实例

4.4. Monitor

Monitor是一种同步机制,依赖于操作系统底层的Mutex Lock(同步锁)来实现同步,在Java中,每一个Java对象都会关联一个Monitor对象,synchronized关键字就是通过Monitor来实现线程同步的,是重量级锁

Monitor的组成部分:

  • owner(所有者):用于存放当前拥有了Monitor对象的线程,也就是拥有对象锁的线程,只有owner线程才能执行同步代码块.
  • waitlist(等待队列):用于存放因调用了wait方法而处于等待中的线程,同时释放该对象锁
  • EntryList(入口队列):用于存放尝试获取对象锁未成功而处于阻塞状态中的线程,当owner释放对象锁时,会唤醒EntryList中的线程来竞争对象锁,成功者成为会owner,失败者则继续等待

Monitor的执行流程:

  1. 第一个进入synchronized代码块的线程,首先尝试获取对象锁,如果锁是空闲状态,则获取到锁,成为owner。如果锁已被其他线程占用,则进入阻塞
  2. 其他访问synchronized代码块的线程尝试获取对象锁未成功,处于阻塞状态,进入EntryList队列,等待对象锁的释放
  3. synchronized代码块执行完毕后,会释放该对象锁,同时唤醒EntryList中阻塞的线程来竞争对象锁,竞争成功的线程成为新的owner,失败的线程则继续等待
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-04-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档