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

    文章

    2767

    浏览量

    72769
  • 代码
    +关注

    关注

    30

    文章

    4556

    浏览量

    66772
  • JVM
    JVM
    +关注

    关注

    0

    文章

    152

    浏览量

    12129
收藏 人收藏

    评论

    相关推荐

    MATLAB2013中Synchronized 6-Pulse Generator在哪儿

    MATLAB2013中Synchronized 6-Pulse Generator在哪儿着实找不到
    发表于 04-19 11:47

    电子膨胀阀在冷库中的应用

    在冷库中,如果要使用热力膨胀阀,在环境温度较低的时候,其感温包内部的感温介质的压力变化大大减小,反应滞后或者毫无反应是常有的事情,严重影响了调节性能。而对于电子膨胀阀来说,虽然电子膨胀阀没有自带的感
    发表于 04-22 13:56

    电子膨胀阀如何驱动

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

    电子膨胀阀注意事项

    `电子膨胀阀注意事项:1. 为防止电机的油份积存及对驱动螺丝的负荷,电子膨胀阀安装位置为电机在正上方,与本体轴心垂直(±15°)。2. 为防止异物造成误作动,电子膨胀阀入口安装100目的网,防止异物
    发表于 04-30 13:58

    电子膨胀阀的介绍

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

    膨胀阀的结构和工作原理

    膨胀阀的结构和工作原理 1 热力膨胀阀的作用:   热力膨胀阀安装在蒸发器入口,常称为膨胀阀,主要作用有两个:  1) 节流做用:高温高压的液态制
    发表于 10-25 14:19 4.6w次阅读
    <b class='flag-5'>膨胀</b>阀的结构和工作原理

    Synchronized multi-spark modul

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

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

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

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

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

    硅胶泡棉对电芯膨胀力和膨胀厚度的影响

    锂离子电池是一个电-热-力耦合系统,在实际使用过程中会存在膨胀问题,一方面是化成过程形成SEI膜,产生气体,电池内部的气压增加,并且随着循环的进行,SEI膜厚度增大,从而造成电芯的膨胀
    的头像 发表于 09-29 09:36 1426次阅读

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

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

    synchronized知识合集1

    * 线程安全 * 什么是synchronized关键字? * synchronized实现方式 * 1.修饰实例方法 * 2.修饰静态方法 * 3.修饰代码
    的头像 发表于 05-11 11:07 303次阅读
    <b class='flag-5'>synchronized</b>知识合集1

    synchronized知识合集2

    * 线程安全 * 什么是synchronized关键字? * synchronized实现方式 * 1.修饰实例方法 * 2.修饰静态方法 * 3.修饰代码
    的头像 发表于 05-11 11:08 269次阅读

    synchronized的原理与四种用法介绍

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

    synchronized 的几种错误用法

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