0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

synchronized的锁膨胀

科技绿洲 来源:Java技术指北 作者:Java技术指北 2023-10-10 16:58 次阅读

初识

synchronized 可以加在方法和类上面,作用于类和对象。下面代码中列出了 synchronized 的用法。

public class SynchronizedTest {

    public static final Object lock = new Object();

    // 锁的是SynchronizedTest.class对象
    public static synchronized void sync1() {

    }

    // 锁的是SynchronizedTest.class对象
    public static void sync2() {
        synchronized (SynchronizedTest.class) {

        }
    }

    // 锁的是当前实例this
    public synchronized void sync3() {

    }

    // 锁的是当前实例this
    public void sync4() {
        synchronized (this) {

        }
    }

    // 锁的是指定对象lock
    public void sync5() {
        synchronized (lock) {

        }
    }
}

synchronized 大家都知道是用 monitorenter 和 monitorexit 两个指令锁住同步块的。

那么 synchronized 是怎么膨胀的呢?为什么会膨胀呢?

先从 JVM 内存开始讲起,对象在被实例化后,是存放在堆内存中的,它由 3 部分组成:

  1. 对象头:存放对象运行时的状态的信息、指向该对象所属 Class 的元数据的指针。
  2. 实例数据:存放对象的属性数据信息,包括父类的信息。
  3. 对齐填充字节:由于虚拟机要求对象的大小必须是 8 字节的整数倍。不是必须存在,仅仅是为了字节对齐。

其中对象头里面包含了 Mark Word(标记字段)和 Class Pointer(类型指针)

图片

  1. Mark Word 默认的存储对象的 hashcode、分代年龄、是否偏向锁、锁标识位的信息,它在运行期间的存储内容会随着锁的变化而变化。
Mark Word (32 bits)是否偏向锁锁标识位值锁状态
对象的hashcode(25)、分代年龄(4)、是否偏向锁(1)、锁标识位(2)001无锁
线程ID(23)、偏向时间戳(2)、分代年龄(4)、是否偏向锁(1)、锁标识位(2)101偏向锁
指向栈中锁记录的指针(30)、锁标识位(2)00轻量级锁
指向重量级锁的指针(30)、锁标识位(2)10重量级锁
  1. Class Pointer(类型指针):对象指向类的元数据的指针,虚拟机通过这个指针来确定对象是哪一个类的实例。

锁膨胀

偏向锁、轻量级锁、重量级锁、自旋锁,这些都是Synchronzied的锁的实现。Synchrozied会根据不同的场景选择不同的锁,我们只使用Synchronzied,不用关心它具体使用的哪个锁。

偏向锁

java 程序中,大多数情况不存在多个线程同时竞争锁,往往都是同一个线程多次获得同一个锁。

当只有一个线程在竞争锁的时候,在线程获取到锁后,将进入偏向模式,程序会将对象的头的前 23 个字节用 CAS 的方式存储线程 ID。下次有线程竞争锁,只需要比较对象头中的线程 ID 是不是和此时获取到锁的线程 ID 相同。如果相同线程就直接进入同步代码块,不需要 CAS 竞争锁。

图片

有另外的线程在竞争锁的时候,持有偏向锁的线程才会释放锁,持有偏向锁的线程不会主动释放偏向锁。偏向锁的撤销,是在没有字节码执行的时候进行的。首先会暂停偏向锁的线程,判断锁对象是否被锁住。撤销偏向锁后恢复成无锁或者是轻量级锁。

轻量级锁

当有另外的线程在竞争偏向锁的时候并且竞争失败了,偏向锁就会膨胀为轻量级锁,其他的线程会通过自旋的方式尝试获取锁。

JVM 会在当前线程的栈帧中创建一个叫做锁记录(Lock Record)的空间,将锁对象的 Mark Word 复制进去。这个官方称为 Displaced Mard Word。然后 JVM 将使用 CAS 操作尝试将锁对象的Mark Word 更新为指向 Lock Record 的指针。如果更新成功,锁标识位就成为 00,此时为轻量级锁。

图片

重量级锁

从上面的表格中就指出重量级锁的对象头里面存储的是指向 monitor 的指针,那 monitor 是什么呢?

monitor 又称为管程,Java 中由 ObjectMonitor 实现。当线程要将对象加锁的时候,对象会创建一个monitor。

图片

ObjectMonitor 主要的字段有:

  1. owner:就是当前加锁的线程
  2. waitSet:就是 owner的线程调用了 wait() 方法,就进入这个里面
  3. entryList:加锁失败的线程阻塞在这个里面
  4. recursions:锁的重入次数
  5. count:用来记录是不是有对象加锁:0.当前对象没有线程加锁,1. 当前对象有线程加锁

从轻量级锁升级到重量级锁的时候,对象头 Mark Word 存储已经变成了指向 Monitor 的指针。线程可以通过这个指针找到 ObjectMonitor,放入 entryList 等待重量级锁释放后竞争。entryList 中的线程 CAS 尝试更新 count = 1,当更新成功后将 owner 设置为当前的线程。当 owner 的线程调用了 wait() 方法,线程就会释放锁,进入 waitSet 中。这个时候 count = 1,owner = null,entryList 的线程可以再次竞争锁。

图片

总结

  1. synchronized 不管是加在类上还是方法上,如果作用在类上,这个类的所有对象都是同一把锁,
  2. 锁膨胀时不可以降级的
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 内存
    +关注

    关注

    8

    文章

    2996

    浏览量

    73869
  • 代码
    +关注

    关注

    30

    文章

    4741

    浏览量

    68325
  • JVM
    JVM
    +关注

    关注

    0

    文章

    157

    浏览量

    12206
收藏 人收藏

    评论

    相关推荐

    电子膨胀阀如何驱动

    `电子膨胀阀的驱动方式是控制器通过对传感器采集得到的参数进行计算,向驱动板发出调节指令,由驱动板向电子膨胀阀输出电信号,驱动电子膨胀阀的动作。电子膨胀阀从全闭到全开状态其用时仅需几秒钟
    发表于 04-29 15:10

    电子膨胀阀的介绍

    一、电子膨胀阀的介绍电子膨胀阀是一种可按预设程序调节进入制冷装置的制冷剂流量的节流元件。在一些负荷变化较剧烈或运行工况范围较宽的场合,传统的节流元件(如毛细管、热力膨胀阀等)已不能满足舒适...
    发表于 02-17 06:48

    电池膨胀原因分析

    电池膨胀原因分析 一般电池电池膨胀的主要原因是:
    发表于 10-21 10:41 1033次阅读

    Synchronized multi-spark modul

    Synchronized multi-spark module (SMSM) for Electronic Ignition Devices (EID)
    发表于 12-29 09:09 829次阅读
    <b class='flag-5'>Synchronized</b> multi-spark modul

    热力膨胀阀的分类及有什么区别_热力膨胀阀怎么调节(工作原理及作用)

    本文以热力膨胀阀为中心,主要介绍了什么是热力膨胀阀,热力膨胀阀的结构、作用与工作原理。详细的说明了热力膨胀阀的分类及区别分析。最后说明了热力膨胀
    发表于 12-26 11:03 3.1w次阅读
    热力<b class='flag-5'>膨胀</b>阀的分类及有什么区别_热力<b class='flag-5'>膨胀</b>阀怎么调节(工作原理及作用)

    电子膨胀阀坏了会怎样_电子膨胀阀怎么测好坏

    本文首先介绍了电子膨胀阀结构及工作原理,其次介绍了电子膨胀阀坏了的原因及常见电子膨胀阀坏故障处理,最后介绍了变频空调电子膨胀阀检测技巧。
    的头像 发表于 05-25 15:53 4.7w次阅读
    电子<b class='flag-5'>膨胀</b>阀坏了会怎样_电子<b class='flag-5'>膨胀</b>阀怎么测好坏

    电子膨胀阀如何选型_电子膨胀阀5线怎样区分

    本文首先介绍了电子膨胀阀的原理,其次介绍了电子膨胀阀的选型表及电子膨胀阀5线的区分,最后介绍了电子膨胀阀的两个典型应用。
    的头像 发表于 05-25 16:22 4.3w次阅读
    电子<b class='flag-5'>膨胀</b>阀如何选型_电子<b class='flag-5'>膨胀</b>阀5线怎样区分

    国内智能市场急剧膨胀,企业做好突围准备势在必行

    近几年,智能的市场发展态势一片大好,特别是在刚过去的2017年,国内智能市场急剧膨胀,上千品牌如雨后春笋般冒出,然而在这样的情况下,众多品牌却无法被市场所消化。所以, 2018年,对智能
    发表于 10-25 14:45 462次阅读

    为何膨胀螺丝可以固定得那么牢固

    很小,从而使墙体、膨胀管及圆锥间形成摩擦自,进而达到固定作用。 膨胀螺丝上的弹簧垫是标准零件,因为它的开口错开并具有弹性,所以叫做弹簧垫圈,弹簧垫圈的作用是利用错口的锐利尖角刺入螺母和平垫中,防止螺母松动。
    的头像 发表于 09-27 10:23 3430次阅读

    Java并发编程中线程同步的常用手段synchronized用法

    synchronized关键字是Java并发编程中线程同步的常用手段之一,其作用有三个: 互斥性:确保线程互斥的访问同步代,自动释放,多个线程操作同个代码块或函数必须排队获得, 可见性:保证共享
    的头像 发表于 04-04 11:30 1156次阅读
    Java并发编程中线程同步的常用手段<b class='flag-5'>synchronized</b>用法

    详细介绍synchronized和Object的关键方法和虚拟机实现原理

    编程过程中经常会遇到线程的同步问题,Java 中对同步问题的解决方案比较多(synchronized、JUC、原子操作、volatile、条件变量等),其中synchronized 最方便、简单易用,也是java 编程中使用最多的临界区保护方案。
    的头像 发表于 03-13 10:06 1225次阅读

    synchronized知识合集1

    * synchronized关键字底层原理 * synchronized修饰实例方法 * monitor是什么? * Java对象内存布局 * synchroni
    的头像 发表于 05-11 11:07 434次阅读
    <b class='flag-5'>synchronized</b>知识合集1

    synchronized知识合集2

    * synchronized关键字底层原理 * synchronized修饰实例方法 * monitor是什么? * Java对象内存布局 * synchroni
    的头像 发表于 05-11 11:08 385次阅读

    synchronized的原理与四种用法介绍

    JDK提供的分两种,一种是JVM实现的synchronized,是java的关键字,因此在这个关键字作用对象的范围内都是可以保证原子性的,主要是依赖特殊的CPU指令。另一种是JDK提供的代码层面的Lock。
    的头像 发表于 06-09 16:13 986次阅读
    <b class='flag-5'>synchronized</b>的原理与四种用法介绍

    synchronized 的几种错误用法

    synchronized 在我们平常工作中也是挺常用的, 对于摆脱多线程问题很有帮助。但是如果synchronized被错误使用时,可能会给我们带来很多麻烦。 在本文中,我们将讨论与同步相关的一些
    的头像 发表于 10-09 10:25 619次阅读