Synchronized 锁机制

2024-01-21

为了避免临界区的竞态条件发生,可以用非阻塞式的原子变量,也可以用阻塞式的锁。Java 多线程的锁都是 对象锁 ,采用互斥的方式让同一时刻只有一个线程能够持有对象锁,从而进入临界区,而其它线程只能阻塞等待,因此不用担心线程上下文切换造成共享资源错乱。

使用方式


  

java

复制代码

// 形式1:关键字在实例方法上,锁为当前实例 public synchronized void instanceLock() { // code } // 形式2:关键字在静态方法上,锁为当前 Class 对象 public static synchronized void classLock() { // code } // 形式3:关键字在代码块上,锁为括号里面的对象 public void blockLock() { Object o = new Object(); synchronized (o) { // code } } // 等价于形式1,锁为当前实例 public void blockLock() { synchronized (this) { // code } } // 等价于形式2,锁为当前Class对象 public void blockLock() { synchronized (this.getClass()) { // code } }

原理 - Monitor

了解 Monitor 之前首先要知道对象在 JVM 中的内存布局,主要包括:

  • 对象头:存储对象的基础信息,GC状态、元数据等
    • Mark Word:对象标记字段,存储一些标记位,如哈希码、锁状态,分代年龄等
    • Klass Pointer:指向对象对应的 Class 对象
  • 实例数据:存储对象实例数据
  • 对齐填充:填充至 8Byte 整数倍

其中跟锁相关的数据在对象头的 Mark Word 中。

JVM 中的每个对象都会关联一个 Monitor 监视器,或者叫管程,一旦某个线程使用 synchronized 给对象上锁(重量级锁),该对象的 Mark Word 中就会记录下对应的 Monitor 指针,同时 Monitor 对象内部的 Owner 字段也会设置为该线程,就像图中的 Thead-2。

如果后续有其它线程试图对同一个对象进行上锁,首先会进行自旋重试上锁,如果一直失败就会被封装成 ObjectWaiter 附在 Monitor 的 EntryList 列表中,然后调用 park 挂起进入阻塞状态,等待被唤醒。而当 Thread-2 退出临界区之后,就会根据某种策略通过 unpark 主动唤醒 EntryList 中的某个线程。

从字节码角度看,JVM 是通过 monitorenter/monitorexit 两个指令实现上锁和解锁的,底层依赖于 OS 的 Mutex Lock,需要额外的用户态到内核态切换的开销,因此称这种上锁为重量级锁,也是 JDK 1.6 之前 synchronized 关键字基本的上锁原理。

锁优化

在 JDK 1.6 之前,synchronized 只有上述基于 Monitor 的锁机制,但是经调研发现,实际的程序在运行过程中,锁资源的竞争并没有那么激烈,如果每次都关联 Monitor 修改 Mark Word 操作会很浪费性能,因此 JVM 后续做了很多优化措施,来提高没有多线程竞争或基本没有竞争的场景下的并发性能。

轻量级锁

我们先退一步,假设一个锁资源被多个线程共享,但它们加锁的事件是错开的,即不存在竞争,那么可以用轻量级锁来优化,在轻量级锁中不涉及 Monitor 对象。在此之前,需要知道每个线程的栈帧里都会包含一个 Lock Record 锁记录,其中主要有两部分:

  • 地址:该 Lock Record 的地址
  • Object Reference:对象引用

进入临界区

当一个线程执行 synchronized 对某个 object 上锁时,首先会尝试 CAS 交换 Lock Record 地址和该 object 的 Mark Word,如果替换成功,表示由该线程给 object 上了锁。

而如果替换失败,那么会对应两种情况:

  1. 其它线程已经持有该 object 的轻量级锁,表示有竞争,那么会进入 锁膨胀
    • 为 object 申请 Monitor 对象,并让 Mark Word 指向该 Monitor
    • 然后自己进入 Monitor 的 EntryList 转为阻塞状态

  1. 如果是自己已经持有 该 object 的轻量级锁,表示重入,那么会再创建一条 Lock Record 作为重入的计数器,并且该锁记录的地址字段为 null

退出临界区

当退出临界区解锁时,也有两种情况:

  1. 如果锁记录取值为 null,表示有重入,重入计数 -1
  2. 如果锁记录不为 null,那么 CAS 交换回 Mark Word 和 Lock Record 地址,此时有两种结果
    • CAS 成功,解锁完成
    • CAS 失败,说明轻量级锁进行了锁膨胀,升级为了重量级锁,之后进入重量级锁解锁流程

轻量级锁适用于两个线程交替执行的场景,如果有竞争,直接膨胀为重量级锁,没有自旋操作。

偏向锁

我们再退一步,如果一个共享资源竞争很少,一直由某个线程上锁,那么轻量级锁就没有必要每次都 CAS 交换 Lock Record 地址和 object 的 Mark Word 了,因此可以进一步优化:第一次上锁时使用 CAS 交换 Thread ID 和 Mark Word,后续只要校验 object 的 Mark Word 里存储的 Thread ID 仍是自己,判断没有发生竞争,这个对象就归该线程所持有,这样就仅需要一次 CAS 操作了。从机制上也能发现,偏向锁解锁后对象头里依然存储着线程 ID,并且这里的 ID 是 OS 分配的,和 Java 层面的线程ID 并不一致。。

需要注意的是:

  • 偏向锁开启时,即对象创建后,Mark Word 后三位为 101,thread/epoch/age 都为 0
  • 如果用 -XX:-UseBiasedLocking 禁用偏向锁,那么对象创建后,Mark Word 后三位为 001,hashcode/age 都为 0,直到第一次用到 hashcode 时才会赋值
  • 偏向锁的对象头里存储了线程 ID,没有空间存储 hashcode 了,所以如果调用 hashCode 会撤销偏向锁,恢复为无锁状态
    • 轻量级锁在锁记录存储 hashcode
    • 重量级锁在 Monitor 中存储 hashcode
  • 如果校验时发现线程不一致,说明有竞争,偏向锁将会被撤销,升级为轻量级锁
    • 撤销超过 20 次,JVM 会重偏向至加锁的 Thread ID
    • 撤销超过 40 次,JVM 会将该类的所有对象设为不可偏向,包括新建对象
  • 如果调用 wait/notify,会撤销偏向锁升级为重量级锁
  • 偏向锁有延迟机制,默认4s,防止初始阶段大量初始化工作产生大量锁撤销和锁升级,影响启动效率,可以通过 -XX:BiasedLockingStartupDelay=0 禁用延迟

如果业务存在大量线程竞争,由于偏向锁撤销存在一定开销,并不能提高性能,反而会影响并发性能,因此偏向锁适用于单个线程重入的场景,在 JDK 15 之后已经默认关闭了偏向锁。

其它

自旋锁

在竞争重量级锁时,如果一个线程尝试获取一个被其他线程持有的锁时,它不会立即进入阻塞状态,而是会在原地进行自旋等待,如果自旋期间持锁线程正好退出同步块释放了锁,那么该线程就可以拿到锁资源而不用进入阻塞再恢复,进行上下文切换了。

  • 自旋会占用 CPU 时间,因此适合多 CPU 环境
  • 自旋锁是自适应的,自旋成功次数多,自旋的机会也会越多

锁消除

锁消除是一种编译器优化技术,用于消除不必要的锁竞争。编译器通过分析代码的语义和数据流来确定哪些锁是不必要的,并消除这些锁。例如,如果一个线程在获取一个锁后执行了一个不可能产生并发异常的代码段,那么这个锁就是不必要的,在这种情况下,编译器可能会消除这个锁,从而提高并发性能。

锁粗化

当一个线程在一段时间内多次重复获得同一个锁,JVM可能会将这个锁的粒度从对象级别提升到更高的级别,例如一个方法或一个类。这种技术被称为锁粗化,可以减少线程对锁的请求频率,从而减少线程上下文切换的开销,提高并发性能。例如,如果一个线程在循环中多次访问同一个对象并获取该对象的锁,JVM可能会将这个锁扩展到包含整个循环的代码块,而不是每次迭代都获取和释放锁。

完整流程

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Synchronized 锁机制 的相关文章

随机推荐

  • 高精度磁导航传感器MGS系列RS232|RS485|CANBUS通讯连线方法

    高精度磁导航传感器MGS系列 包含 CNS MGS 080N CNS MGS 160N等 具有1mm的检测精度 特别适应于 精度磁条导航 利 检测磁场相对位置来进 AGV的辅助定位对接 获得更 的导航 定位 驻 精度 MGS系列磁导航传感器
  • 给文件夹添加备注,保姆版?

    文件夹里的文件太多 太乱怎么办 这么办 怎么做 3 1 如果没有备注这一栏 鼠标右键这里 将备注勾选 3 2 文件夹顶部 查看 选项 3 3 查看 不勾选 隐藏受保护系统文件 显示隐藏文件 文件夹 点击应用 确认 3 4 选择要备注的文件夹
  • 有效降低信号串扰的PCB设计原则

    降低信号串扰的一些PCB设计建议 1 对于传输线 保持相邻信号线之间的间距至少为两倍信号线宽 2 尽量避免信号跨越返回路径中的不连续点或者空隙 3 如果必须在返回路径中跨越空隙 则尽量使用差分线 4 电容器不是一种低阻抗互连结构 其高频阻抗
  • 有机小分子化合物的核磁H谱图分析教程-科学指南针

    1 核磁分析的原理 核磁共振波谱法 Nuclear Magnetic Resonance Spectroscopy NMR NMR是研究原子核对射频辐射 Radio frequency Radiation 的吸收 它是对各种有机和无机物的成
  • 国外拨号VPS指南:开启你的全球网络之旅

    在当今数字化时代 互联网已经成为了我们生活的一部分 而要在全球范围内畅通无阻地访问互联网 拥有一个可靠的国外拨号VPS是非常重要的 无论您是为了工作 学习还是娱乐 国外拨号VPS都可以为您提供更广泛的网络体验 本文将为您提供国外拨号VPS的
  • (2024最新整理)Java最全八股文及答案!

    Java的特点 Java是一门面向对象的编程语言 面向对象和面向过程的区别参考下一个问题 Java具有平台独立性和移植性 Java有一句口号 Write once run anywhere 一次编写 到处运行 这也是Java的魅力所在 而实
  • 短视频时代:影响播放量的秘密与破解之道

    在当下这个信息爆炸的时代 短视频已经成为我们日常生活的一部分 无论是刷朋友圈 看新闻还是消磨时光 短视频都是我们的首选 正因为如此 许多自媒体人和内容创作者纷纷投身到这片热土 希望通过短视频实现自己的价值 然而 许多人在创作过程中都会遇到一
  • 你知道修图软件手机端的哪些比较好用吗?分享我的爱用工具

    你是否经常在朋友圈看到朋友晒出的照片 美得如同画中景 让人惊叹不已 你是否也曾羡慕过那些轻松将普通照片变成艺术大片的摄影高手 其实 他们背后的 魔法 大多都来自于使用p图软件给图片进行美化 今天 就让我们一起来探讨一下 p图软件哪个好用免费
  • 史上最全Java面试八股文(带全部答案)2024年最新版

    今天要谈的主题是关于求职 求职是在每个技术人员的生涯中都要经历多次 对于我们大部分人而言 在进入自己心仪的公司之前少不了准备工作 有一份全面细致 面试题 将帮助我们减少许多麻烦 在跳槽季来临之前 特地做这个系列的文章 一方面帮助自己巩固下基
  • CIO必备技能,手把手教你做好企业信息化规划

    很多公司在做信息系统实施的时候 我都会要求他们先做一件事 顶层设计 用大白话说就是IT规划或者信息化规划 那么到底什么是信息化规划 中小企业适不适合去做信息化规划 该怎么做 由谁去做 本着说人话 不废话的原则 这篇给大家分享关于企业信息化建
  • AI-基于Langchain-Chatchat和chatglm3-6b部署私有本地知识库

    目录 参考 概述 部署安装 环境准备 原理和流程图 一键启动 启动WebAPI 服务 启动WebUI服务 Docker部署
  • 计算机Java项目|尤文图斯足球俱乐部网上商城系统

    作者简介 Java领域优质创作者 CSDN博客专家 CSDN内容合伙人 掘金特邀作者 阿里云博客专家 51CTO特邀作者 多年架构师设计经验 腾讯课堂常驻讲师 主要内容 Java项目 Python项目 前端项目 人工智能与大数据 简历模板
  • 微信小程序|SSM微信小程序的学生选课系统

    作者简介 Java领域优质创作者 CSDN博客专家 CSDN内容合伙人 掘金特邀作者 阿里云博客专家 51CTO特邀作者 多年架构师设计经验 腾讯课堂常驻讲师 主要内容 Java项目 Python项目 前端项目 人工智能与大数据 简历模板
  • 申泰勇教练的独家人物化身系列即将登陆 The Sandbox

    申泰勇 Shin Tae yong 教练是足球界的传奇人物 他来到 The Sandbox 推出了自己的专属人物化身系列 作为前 K 联赛中场球员和印尼队取得历史性成就的幕后教练 他的传奇经历现在已经影响到了虚拟世界 向过去 现在和未来致敬
  • 基于springboot+vue实现汽车改装方案网站演示【附项目源码+论文说明】

    基于springboot vue实现汽车改装方案网站演示 摘要 本文主要讲述了基于SpringBoot MySql开发技术开发的汽车改装方案网站的设计与实现 这里的汽车改装方案网站是通过一个平台使所有的汽车爱好者们可以不用出门就可以体验到专
  • 最新整理Java面试八股文,大厂必备神器

    在看这篇文章之前 我想我们需要先搞明白八股文是什么 明清科举考试的一种文体 也称制义 制艺 时文 八比文 八股文章就四书五经取题 内容必须用古人的语气 绝对不允许自由发挥 而句子的长短 字的繁简 声调高低等也都要相对成文 字数也有限制 八股
  • 贴近速度的选择:为什么美国快速VPS值得您投资

    随着互联网的普及 速度已经成为了一个至关重要的因素 无论您是个人用户还是企业所有者 快速的互联网连接都能够提高您的在线体验和生产力 在这个背景下 美国快速VPS变得越来越受欢迎 本文将探讨为什么选择美国快速VPS是一个明智的决策 并提供有关
  • 基于springboot+vue实现实企业任务管理追踪系统【附项目源码+论文说明】

    基于springboot vue实现实企业任务管理追踪系统 摘要 随着时代的进步 人们现在通过计算机线上化的办公方式成功的提升了日常办公的效率 通过线上办公能够有效地提升信息传递的效率 可以快速的完成任务的流程处理 邮件的发送等等功能 并且
  • 计算机Java项目|基于SSM的篮球系列网上商城设计与实现

    作者简介 Java领域优质创作者 CSDN博客专家 CSDN内容合伙人 掘金特邀作者 阿里云博客专家 51CTO特邀作者 多年架构师设计经验 腾讯课堂常驻讲师 主要内容 Java项目 Python项目 前端项目 人工智能与大数据 简历模板
  • Synchronized 锁机制

    为了避免临界区的竞态条件发生 可以用非阻塞式的原子变量 也可以用阻塞式的锁 Java 多线程的锁都是 对象锁 采用互斥的方式让同一时刻只有一个线程能够持有对象锁 从而进入临界区 而其它线程只能阻塞等待 因此不用担心线程上下文切换造成共享资源