多线程:Synchronized实现原理

synchronized原理详解(通俗易懂超级好) 目标 【理解】synchronized底层原理 【掌握】synchronized 的用法 目录目标一、synchronized原理1.1 原子性1.2 可见性1.3 有序性1.4 可重入性二、synchronized 的用法三、synchronized 的底层原理3.1 对象头在JVM中存储的形式3.1.1 对象头3.1.2 对象实例数据3.1.3 对齐填充3.2 Monitor3.3 synchronized锁的优化3.3.1 synchronized锁的状态3.3.2 偏向锁3.3.3. 轻量级锁3. 阅读详情

前言:

Synchronize实现实现同步最常用的方式,它的底层是如何实现的?

Synchronized会锁定什么?

Synchronized锁定的是对象,在不同地方使用会锁类对象或实例对象

  1. 实例方法:锁定实例对象
  2. 静态方法:锁定类对象
  3. 代码块
    1. synchronized(this) {}:锁定实例对象
    2. synchronized(class.object){} 锁定类对象

JDK1.6前Synchronized实现:

  1. 通过Synchronized修饰的代码块,线程通过获取Monitor对象,来实现获取锁。在同步代码块的开始会引入monitorenter,在结束的位置引入monitorexit,在访问这一对monitor的时候,线程必须要持有monitor对象,并将这个对象记录在自己的私有monitor record列表中,表示当前线程具有这个对象的锁。每个对象只有一个与之对应的monitor,也就是说monitor只能被一个线程所持有。(线程拥有自己monitor record,对象也有自己的monitor等待队列)
  2. 可重入性:当前线程再次申请所拥有对象的锁时(在同步代码中再次执行被Synchronized修饰的方法),可以再次拿到这个对象的锁。
  3. 被Synchronized修饰的方法,是通过在字节码上添加ACC_Synchronized标志。JVM 通过该
    ACC_SYNCHRONIZED 访问标志来辨别⼀个⽅法是否声明为同步⽅法,如果是实例⽅法,JVM 会尝试获取实例对象的锁。如果是静态⽅法,JVM 会尝试获取当前 class 的锁。
  4. Monitor监视器锁的内容结构
    1. Owner:初始时为NULL表示当前没有任何线程拥有该monitor,当线程成功拥有该锁后保存线程唯一标识,当锁被释放时又设置为NULL;
    2. EntryQ:关联一个系统互斥锁(semaphore),阻塞所有试图锁住monitor record失败的线程
    3. RcThis:表示等待在该monitor的所有线程的个数。
    4. Nest:用来对重入锁次数的计数。

JDK6以后做的优化

锁出现不同类型,无锁状态-偏向锁-轻量锁-重量锁(原Synchronized)
JVM是如何区分锁处于不同状态呢?需要一个位置记录锁出在什么状态,这时候就需要理解Object头

Java对象头(存储锁的类型)

在 HotSpot 虚拟机中,对象在内存中的布局分为三块区域:对象头,实例数据和对齐填充。
对象头中包含两部分:

  • MarkWord(存储锁的类型)
  • 对象的类型指针
  • 如果是数组对象的话,对象头还有一部分是存储数组的长度。

多线程下 synchronized 的加锁就是对同一个对象的对象头中的 MarkWord 中的变量进行CAS操作。

不同类型的锁下MarkWord 的内容

  1. 无锁状态
    在这里插入图片描述

  2. 偏向锁
    在这里插入图片描述

可以看到在偏向锁状态下,相比无锁状态多了线程ID和epoch,且是否是偏向锁变为了1.
注意:如果这个对象计算过hashcode的话,就无法使用偏向锁了(因为没有地方存储对象的hashcode),会发生锁升级。

偏向锁是一种针对加锁操作的优化手段,经过研究发现,在大多数情况下,锁不仅不存在多线程竞争,而且总是由同一线程多次获得,因此为了减少同一线程获取锁(会涉及到一些CAS操作,耗时)的代价而引入偏向锁。

  1. 轻量锁、重量锁
    在这里插入图片描述

轻量锁这里指向持有锁的线程,它内部的栈帧中的 Lock Record 记录。

重量锁这也就是指向1.6之前的Monitor监视器对象。

64位的JVM打印对象头信息

    public static void biasedSyn() {
    //  偏向锁在应用程序启动后的几秒钟内(默认延迟为4秒)才会激活,所以此处主线程休眠5秒之后,创建的对象默认启动偏向锁
        ThreadUtil.sleepSeconds(5);
        Object o = new Object();
        System.out.println(o.hashCode());
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
        synchronized (o) {
            System.out.println(ClassLayout.parseInstance(o).toPrintable());
        }
    }

java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           05 00 00 00 (00000101 00000000 00000000 00000000) (5)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           05 38 17 03 (00000101 00111000 00010111 00000011) (51853317)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

mark word是反向存储的,根据mark word是由前64位的value倒序拼接成的串组成,所以Mark Word头部信息如下
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000101

倒数后三位101,表示当前对象处于偏向锁阶段。

锁的升级过程

1、当资源对象处于无锁状态(JDK1.6之后默认使用偏向锁,创建的对象是处于匿名偏向锁状态,注意偏向锁在应用程序启动后的几秒钟内(默认延迟为4秒)才会激活,所以5秒之后,创建的对象默认启动偏向锁)
通过synchronized加锁之前,对象未进行过hashcode —— 偏向锁
通过synchronized加锁之前,对象进行过hashcode —— 轻量锁
如何升级:通过使用 CAS 将 MarkWord 中的线程ID设置为自己的线程ID,就升级为偏心锁

2、当资源对象处于偏向锁状态

  1. 加锁
    • 如果持有锁的线程再次申请锁,会直接获取锁(偏向的含义)
    • 如何请求加锁的线程 ID 不是持有锁的线程 ID,需要进行锁升级(升级需要进行偏向锁的撤销)
  2. 撤销
    • MarkWord 中指向的线程不存活,退回到可偏向但未偏向的状态
    • MarkWord 中的线程存活
      • 线程ID指向的线程仍然拥有锁,升级为轻量级锁,将 mark word 复制到线程栈中
      • 不再拥有锁,退回到可偏向但未偏向的状态

3、当资源对象要变为轻量锁状态

  1. 加锁
    • 线程尝试使用 CAS 将对象头中的 Mark Word 替换为指向线程中锁记录(Lock Record)的地址。如果成功,当前线程获得轻量级锁,如果失败,虚拟机先检查当前对象头的 Mark Word 是否指向当前线程的栈帧,如果指向,则说明当前线程已经拥有这个对象的锁,则可以直接进入同步块 执行操作,否则表示其他线程竞争锁,当前线程便尝试使用自旋来获取锁。当竞争线程的自旋次数 达到界限值(threshold),轻量级锁将会膨胀为重量级锁。
    • 轻量级锁失败后,虚拟机为了避免线程真实地在操作系统层面挂起,还会进行一项称为自旋的优化手段。这是基于在大多数情况下,线程持有锁的时间都不会太长,如果直接挂起操作系统层面的线程可能会得不偿失,毕竟操作系统实现线程之间的切换时需要从用户态转换到核心态,这个状态之间的转换需要相对比较长的时间,时间成本相对较高,因此自旋锁会假设在不久将来,当前的线程可以获得锁,因此虚拟机会让当前想要获取锁的线程做几个空循环(这也是称为自旋的原因),一般不会太久,可能是50个循环或100循环,在经过若干次循环后,如果得到锁,就顺利进入临界区。
  2. 撤销
    • 轻量级锁解锁时,如果对象的Mark Word仍然指向着线程的锁记录,会使用CAS操作, 将修改Mark Word,如果成功,则表示没有竞争发生。如果失败, 表示当前锁存在锁竞争,锁就会膨胀为重量级锁。

3、当资源对象要变为重量锁

  • 重量级锁(heavy weight lock),是使用操作系统互斥量(mutex)来实现的传统锁。
  • 当锁膨胀(inflate)为重量锁时,就不能再退回到轻量级锁。

synchronized 是非公平锁

在线程释放锁的时候,JVM会从等待队列中随机获取一个线程来获取锁。
优点是:因为减少了线程切换的开销,所以非公平锁通常具有更好的性能。
缺点是:可能产生饥饿现象

锁消除

锁消除(lock eliminate):虚拟机的运行时编译器在运行时如果检测到一些要求同步的代码上不可能发生共享数据竞争,则会去掉这些锁。

锁粗化(Lock coarsening)

将临近的代码块用同一个锁合并起来。

头歌操作系统 课堂练习4.2:页式内存管理 答案 无解析 阅读详情

相关推荐

西门子V90 PN伺服控制核心:FB284功能块详解与实战

在工业自动化中,伺服定位控制是运动控制的基础环节,其本质是PLC通过PROFINET协议与伺服驱动器实现高速、确定性数据交互。FB284作为西门子为V90 PN定制的标准化功能块,封装了GSD映射、状态机管理与周期性PDO同步机制,将底层寄存器操作抽象为高可靠调用接口。相比MOVE指令或MC_MoveAbsolute等通用方案,FB284显著降低时序错乱风险,提升多轴同步精度与故障响应能力。它广泛应用于包装、灌装、装配等中端产线,尤其适配S7-1200/1500平台下的快速部署与现场维护。本文聚焦V90 P

weixin_42696271的博客 298

synchronized原理

摘要:Java中的synchronized关键字是实现线程同步的重要机制,具有以下特性:1)作为隐式可重入锁,支持锁升级(偏向锁→轻量级锁→重量级锁);2)保证原子性、可见性和有序性;3)使用方法包括方法加锁和同步代码块。底层原理通过monitor对象实现,JDK1.6后优化了锁机制,引入偏向锁、轻量级锁和自适应自旋锁等策略提升性能。此外,JVM会进行锁粗化和锁消除优化。该机制适用于解决多线程并发问题,但需根据具体场景选择合适的同步策略。

纯洁的小魔鬼 5837

【SABRE 3D, SABRE 3DxT,LAM设备】2025年9月10日

前文:SABRE 3D系列机台简介本章节详细阐述了在维护期间锁定电气、机械、热力学及重力组件以及化学管线输入的锁定操作流程,旨在降低人员受伤风险。p42~p55。

weixin_46735260的博客 1611

一篇就够,synchronized原理详解

synchronized详解 在多线程同时访问一个共享变量时,volatile是一个轻量级的解决方案,但是volatile只能修饰一个变量并且不保证原子性。在Java中还提供了两种方式实现同步互斥访问:synchronized和Lock 其实这些本质上就是加锁, 加锁目的:序列化访问临界资源,即同一时刻只能有一个线程访问临界资源(同步互斥访问) 不过有一点需要区别的是:当多个线程执行一个方法时,该方法内部的局部变量并不是临界资源,因为这些局部变量是在每个线程的 私有栈中,因此不具有共享性,不会导致线程安全

小派师兄 1万+

java modbus通讯协议_Modbus通 讯 协 议

电磁流量计Modbus通 讯 协 议(版本号:9000-K V9.1.1)2020年01月01日通讯协议针对KFD电磁流量计工业应用设计,版本:9000-K V9.1.1,该版本主要用于实时数据采集、流量测量、流量累计控制及部分参数的修改。一、主机系统通讯部件要求1.国际标准RS-485通讯接口部件,不小于11Bytes 的通信缓冲区(FIFO),支持1200、2400、4800、96...

weixin_39956612的博客 1010

Fedproto:原型聚合的联邦学习框架

文中说明,联邦学习通过计算传递梯度聚合模型时,客户端之间的异构性通常会阻碍模型优化收敛和泛化性能。故本文提出新的FedProto框架,将梯度替换成为原型,通过计算、聚合从不同客户端收集到的本地原型,然后将全局原型发送回所有客户端,以规范本地模型的训练。对每个客户机进行局部训练的目的是最小化对本地数据的分类损失,同时保持生成的本地原型足够接近相应的全局原型(损失函数最小+正则)。什么是原型?文中提到:“

weixin_47754029的博客 2649

synchronize原理

本文转自:https://blog.youkuaiyun.com/u011212394/article/details/82228321 一.synchronized的三种应用方式 1.修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁 2.修饰静态方法,作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁 3.修饰代码块,指定加锁对象,对给定对象加锁,进入同步代码库前要获得给定对...

dkingyaoyao的博客 456

电磁炉线圈加热仿真全流程:用Ansys Maxwell分析涡流效应与热损耗

本文详细介绍了使用Ansys Maxwell进行电磁炉线圈加热仿真的全流程。通过构建2D轴对称涡流场模型,深入分析了高频下的涡流效应、趋肤效应与热损耗分布,为优化线圈设计、提升加热效率与均匀性提供了量化依据和实用指南。

sss66的博客 963

Synchronied详解

Synchronied详解

cyh1072630252的博客 263

Vue3 - 超详细最新 wangEditor V5 富文本编辑器安装引入及使用教程,提供工具栏配置、基础富文本功能、API使用示例教程等(新手小白快速引入并植入到项目中)

vue3,wangEditorv5富文本编辑器,wangEditorv5官方文档,vue3最新安装wangEditorv5富文本详细使用教程,vue3使用wangEditorv5编辑器示例代码,vue3网站网页安装植入富文本编辑器教程,vue3wangEditor使用api,vue3安装富文本控制台出现报错如何解决,vue3wangEditor-v5工具栏配置,vue3中使用富文本编译器wangEditor5的方法,wangeditor5在vue3中的全使用过程,vue3超详细最新wangedi

🏆 前端领域优质创作者 4253

YOLOv11 TensorRT极致加速:C++部署性能优化完全指南

购买即可解锁300+YOLO优化文章,并且还有海量深度学习复现项目,价格仅需两杯奶茶的钱,别人有的本专栏也有!

LXY_LOVE36的博客 115

java多线程synchronized_Java多线程:由浅入深看synchronized的底层实现原理

前言前两篇文章,我们聊了聊线程/进程的概念,接着简单串了一下同步的方式方法。今天我们就单拎出来synchronized,好好捋一捋它的前世今生。正文小A:咱们前几天铺垫了这么多内容,今天是不是要好好的深挖一下原理的内容了?MDove:没错,接下来。我会从常见的synchronized加锁方式入手;引出Java对象在内存的布局,以及锁的存放位置;然后看一看锁在C++中的简单实现思路;最后咱们从字节码...

weixin_32626635的博客 149

V4L2教程(1):Ubuntu V4L2开发环境搭建与设备探索

欢迎来到V4L2学习指南的第一篇!本文将带你从零开始,在Ubuntu系统上搭建完整的V4L2视频采集开发环境。无论你是想开发视频监控、视频会议还是机器视觉应用,掌握V4L2都是Linux视频开发的必经之路。 **本节学习目标**: - 理解V4L2的基本概念和架构 - 搭建Ubuntu下的V4L2开发环境 - 掌握v4l2-ctl等调试工具的使用 - 学会检测和配置USB摄像头设备

琅嬛福地 417

Java多线程:优化Synchronized实现原理

我们最初学习Java的时候,遇到多线程我们会知道synchronized,对于当时的我们来说synchronized是保证了多线程之间的同步,也成为了我们解决多线程情况的常用手段。但是,随着我们学习的进行我们知道synchronized是一个重量级锁,相对于Lock,它会显得那么笨重,以至于我们认为它不是那么的高效而慢慢摒弃它。但是,随着Javs SE 1.6对synchronized进行的各种优...

Bobit - 优快云博客 188

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

java synchronized底层原理_java多线程学习十二::::Synchronized及其实现原理

Synchronized是Java中解决并发问题的一种最常用的方法,也是最简单的一种方法。Synchronized的作用主要有三个:(1)确保线程互斥的访问同步代码(2)保证共享变量的修改能够及时可见(3)有效解决重排序问题。Java中每一个对象都可以作为锁,这是synchronized实现同步的基础:普通同步方法,锁是当前实例对象静态同步方法,锁是当前类的class对象同步方法块,锁是括号里面的...

weixin_39523280的博客 96

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

多线程:synchronized的底层实现原理及锁的升级

1、synchronized的使用 a)普通同步方法,锁的是当前实例对象 b)静态同步方法,锁的是当前类对象 c)同步方法块,锁的是Synchronized括号中配置的对象 当一个对象需要方法同步方法或代码块时,需要获取锁,退出或者抛出异常时,必须释放锁 2 Synchronized底层实现 JVM基于进入和退出Monitor对象来实现方法同步和代码块的同步,但是两者的实现细节不同。 代码块同步...

skw1028142506的博客 242

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Java多线程:由浅入深看synchronized的底层实现原理

前言 前两篇文章,我们聊了聊线程/进程的概念,接着简单串了一下同步的方式方法。今天我们就单拎出来synchronized,好好捋一捋它的前世今生。 正文 小A:咱们前几天铺垫了这么多内容,今天是不是要好好的深挖一下原理的内容了? MDove:没错,接下来。我会从常见的synchronized加锁方式入手;引出Java对象在内存的布局,以及锁的存放位置;然后看一看锁在C++中的简单实现...

曾子墨 268

Java多线程(四):Synchronized实现原理

Synchronized 1.synchronized的三种应用方式   1.修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁   2. 静态方法,作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁   3.修饰代码块,指定加锁对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁。 2.synchronized括号后面的对象   synchronized扩后...

scofen的博客 895

[Java多线程 -2]:由浅入深看synchronized的底层实现原理

前言 [从零开启 Java 多线程 - 1 ]:开胃小菜 前俩篇文章,我们聊了聊线程/进程的概念,接着简单串了一下同步的方式方法。今天我们就单拎出来synchronized,好好捋一捋它的前世今生。 正文 小A:咱们前几天铺垫了这么多内容,今天是不是要好好的深挖一下原理的内容了? MDove:没错,接下来。我会从常见的synchronized加锁方式入手;引出Java对象在内存的布局,以及锁的存放...

weixin_34319999的博客 207

java 线程由浅入深_Java多线程:由浅入深看synchronized的底层实现原理

Java多线程:由浅入深看synchronized的底层实现原理-1.jpg (91.72 KB, 下载次数: 0)2018-9-21 03:55 上传前言前俩篇文章,我们聊了聊线程/进程的概念,接着简单串了一下同步的体例体例。今天我们就单拎出来synchronized,好好捋一捋它的前世今生。正文小A:咱们前几天铺垫了这么多内容,今天是不是要好好的深挖一下原理的内容了?MDove:没错,接下来。...

weixin_30696613的博客 128

java 同步锁_Java多线程:synchronized同步锁的使用和实现原理

作用和用法在多线程对共享资源进行并发访问方面,JDK提供了synchronized关键字来进行线程同步,实现多线程并发访问的线程安全。synchronized的作用主要体现在三个方面:(1)确保线程互斥地访问同步代码;(2)保证共享变量的线程可见性;(3)禁止指令重排。其中(2)和(3)相当于volatile关键字的作用。synchronized可以用在代码的以下地方:(1)静态方法:将类对象自身...

weixin_39610422的博客 285

java多线程:跟Synchronized相比, 可重入锁Reentrant Lock其实现原理有什么不同?

其实,锁的实现原理基本是为了达到一个目的:让所有的线程都能看到某种标记。Synchronized通过在对象头中设置标记实现了这一目的,是一种JVM原生的锁实现方式,而ReentrantLock以及所有的基于Lock接口的实现类,都是通过用一个volitile修饰的int型变量,并保证每个线程都能拥有对该int的可见性和原子修改,其本质是基于所谓的AQS框架。可重入锁(Reentrant Lock)和 synchronized 都是用于实现线程同步的机制,但它们的实现原理和特性有一些区别。

学亮编程手记 368

java多线程:为什么说Synchronized是一个悲观锁? 乐观锁的实现原理又是什么?什么是CAS, 它有什么特性?

Synchronized显然是一个悲观锁,因为它的并发策略是悲观的:不管是否会产生竞争,任何的数据操作都必须要加锁、用户态核心态转换、维护锁计数器和检查是否有被阻塞的线程需要被唤醒等操作。随着硬件指令集的发展,我们可以使用基于冲突检测的乐观并发策略。先进行操作,如果没有其他线程征用数据,那操作就成功了;如果共享数据有征用,产生了冲突,那就再进行其他的补偿措施。这种乐观的并发策略的许多实现不需要线程挂起,所以被称为非阻塞同步。

学亮编程手记 555

java多线程:9、synchronized、Lock的底层实现原理以及和volatile、Lock、ReentrantLock的区别?

文章目录1、synchronized的底层实现原理分析2、synchronized和其他关键字的区别(1) synchronized和volatile的区别?(2)synchronized和Lock的区别?(3)synchronized和ReentrantLock的区别? 1、synchronized的底层实现原理分析 2、synchronized和其他关键字的区别 (1) synchronize...

weixin_42924812的博客 742

每线程对应1vcpu_Java多线程:synchronized同步锁的使用和实现原理

作用和用法在多线程对共享资源进行并发访问方面,JDK提供了synchronized关键字来进行线程同步,实现多线程并发访问的线程安全。synchronized的作用主要体现在三个方面:(1)确保线程互斥地访问同步代码;(2)保证共享变量的线程可见性;(3)禁止指令重排。其中(2)和(3)相当于volatile关键字的作用。synchronized可以用在代码的以下地方:(1)静态方法:将类对象自身...

weixin_30114649的博客 176

并发机制的底层实现原理-volatile,synchronized,CAS原子操作

volatile,synchronized,CAS原子操作 定义及原理Volatile的定义和实现原理定义:原理synchronized的定义和实现原理,锁的存储结构定义:原理:CAS定义: Volatile的定义和实现原理 定义: java内存模型保证定义为volatile的变量,在所有的线程中看到的这个变量的值是一致的. 原理 volatile 是如何保证可见性的? 被volatile修饰的变量在JIT生成的汇编语言中,会在此变量的写操作上加上lock前缀的指令,此指令在多核处理器下会引发两件事情

weixin_38219412的博客 527
上一篇: 设计模式:单例对象的多种实现
下一篇: 多线程:乐观和悲观锁
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贝多芬也爱敲代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值