Java Synchronize底层原理总结

 更新时间:2023年06月14日 08:43:24   作者:EzreaLwj  
这篇文章主要给大家总结了Java Synchronize底层原理,文中的图文讲解介绍的非常详细,对我们学习Java Synchronize有一定的帮助,需要的朋友可以参考下

对象内存结构

对象头MarkWord 存储对象头的信息,Klass Word 描述对象实例的具体类型

实例数据:成员变量

对齐填充:如果对象头 + 实例变量 不是 8 的整数倍,则通过对齐填充补齐

MarkWord 解析

  • hashcode:25位的对象标识Hash码
  • age:对象分代年龄占4位
  • biased_lock:偏向锁标识,占1位,0表示没有开始偏向锁,1表示开启了偏向锁
  • thread:持有偏向锁的线程ID,占23位
  • epoch:偏向时间戳,占2位
  • ptr_to_lock_record:轻量级锁状态下,指向栈中锁记录的指针,占30位
  • ptr_to_heavyweight_monitor:重量级锁状态下,指向对象监视器Monitor的指针,占30位

LockRecord 锁记录

Markword:记录锁记录的地址

对象引用:引用被加上锁了的对象

重量级锁

Monitor

Monitor 监视器,是由 jvm 提供的,由 C++ 实现的,有三个实现部分

WaitSet:调用了 wait 方法的线程在这里等待,处于 WAITED 状态

EntryList:没有抢到对象锁的线程在这里等待,处于 BLOCKED 状态

Owner:存储已经抢到锁的线程对象

Monitor 的实现属于重量级锁,涉及到 内核态和用户态的切换线程的上下文切换,每个 Java 对象都会关联一个 Monitor 对象,如果使用 Synchronize 给该对象加锁,那么 Java 对象上面的 MarkWord 地址就被设置为指向该 Monitor 对象的指针

轻量级锁

加锁流程

  • 在线程栈中创建一个 Lock Record 对象,它的 object reference 字段指向锁对象
  • 通过 CAS 指令把 Lock Record 的地址存放到对象头的 Markword 中,如果是无锁状态则修改成功,代表该线程获取了轻量级锁
  • 如果当前线程已经持有该锁,就代表是一次锁重入,设置 Lock Record 的第一部分为 null,起到一个重入计数器的作用
  • 如果 CAS 修改失败,则说明发生了竞争,需要膨胀为重量级锁

解锁过程

  • 遍历线程栈,找到所有 object reference 字段等于当前锁对象的 Lock record
  • 如果 Lock recordMarkWordnull,代表这是一次重入,将 obj 设置为 nullcontinue 即可
  • 如果 Lock recordMarkword 不为 null,则利用 CAS 指令将对象头的 markword 与对象对象头的 markword 进行替换,如果成功则恢复无锁状态,如果失败膨胀重量级锁

Markword 记录

开始时的状态

替换后的状态

偏向锁

背景:轻量级锁在没有竞争的时候,每次重入都需要进行 CAS 操作

Java 6 中 引入偏向锁来做进一步的优化:只有第一次 操才使用 CAS 将线程 ID 设置到对象的 markword 头,之后发现这个线程 ID 是自己就不会产生竞争,不用重新 CAS,以后只要不发生竞争,这个对象就归这个线程所有

代码示例:

public class Thread5 {
    private static final Object object = new Object();
    public static void method1() {
        synchronized (object) {
            method2();
        }
    }
    public static void method2() {
        synchronized (object) {
            method3();
        }
    }
    public static void method3() {
        synchronized (object) {
        }
    }
}

总结

Java 中的 Synchronize 有偏向锁、轻量级锁、重量级锁三种形式,分别对应了锁只被一个线程持有、不同线程交替持有锁、多线程竞争的情况

重量级锁:底层使用 Monitor 实现,里面涉及到了用户态和内核态的转换、进程的上下文切换,成本较高,性能比较低

轻量级锁:线程加锁时间是错开的(也就是没有竞争),可以用轻量级锁来优化,轻量级修改了对象头的锁标志,相对重量级锁性能提升了许多,每次修改都是 CAS 操作,保证原子性

偏向锁:一段很长的时间内都只被一个线程使用锁,可以使用偏向锁,第一次获得锁时,会有一个 CAS 操作,之后该线程再获取锁,只需要判断 mark word 中是否是自己的线程 id 即可,而不是开销相对较大的 CAS 命令

以上就是Java Synchronize底层原理总结的详细内容,更多关于Java Synchronize底层原理的资料请关注脚本之家其它相关文章!

相关文章

  • hibernate和mybatis对比分析

    hibernate和mybatis对比分析

    通过本文给分享了hibernate和mybatis对比分析,从开发对比,系统调优对比,对象管理与抓取策略,缓存机制对比等方面给大家详细介绍,需要的朋友参考下吧
    2017-09-09
  • Java中反射详解

    Java中反射详解

    本文主要介绍了Java中反射的相关知识。具有很好的参考价值,下面跟着小编一起来看下吧
    2017-02-02
  • spring无法读取properties文件数据问题详解

    spring无法读取properties文件数据问题详解

    这篇文章主要介绍了spring无法读取properties文件数据问题详解,需要的朋友可以参考下
    2020-02-02
  • Java 重试框架 Sisyphus 配置的两种方式

    Java 重试框架 Sisyphus 配置的两种方式

    这一节让我们一起学习下 sisyphus 基于函数式的配置和注解式的配置。为了满足更加方便的配置,Retryer 类提供了许多可以配置的信息。下面一起进入文章了解详情内容
    2021-11-11
  • Java同学找工作最懵圈的问题:到底啥是分布式系统开发经验?(推荐)

    Java同学找工作最懵圈的问题:到底啥是分布式系统开发经验?(推荐)

    这篇文章主要介绍了分布式系统开发经验,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-04-04
  • MyBatis中一对多的xml配置方式(嵌套查询/嵌套结果)

    MyBatis中一对多的xml配置方式(嵌套查询/嵌套结果)

    这篇文章主要介绍了MyBatis中一对多的xml配置方式(嵌套查询/嵌套结果),具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • java实现IP地址转换

    java实现IP地址转换

    这篇文章主要为大家详细介绍了java实现IP地址转换,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-11-11
  • Java实现threadLocal线程池获取

    Java实现threadLocal线程池获取

    本文主要介绍了Java实现threadLocal线程池获取,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07
  • Java实现顺时针输出螺旋二维数组的方法示例

    Java实现顺时针输出螺旋二维数组的方法示例

    这篇文章主要介绍了利用Java如何实现顺时针输出螺旋二维数组的方法示例,文中给出了详细的示例代码和注释,相信对大家具有一定的参考价值,有需要的朋友们下面来一起看看吧。
    2017-02-02
  • Spring自动装配bean的方式总结

    Spring自动装配bean的方式总结

    这篇主要介绍了Spring自动装配Bean的方式总结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2024-01-01

最新评论