synchronized底层原理

2023-10-31

一探究竟:反编译

三种使用场景,示例代码;

public class SynchronizePrincipe {

    public synchronized static void fun1(){}
    public synchronized void fun2(){}
    public void fun3() {
        synchronized (this){}
    }
}

通过javap -c -v命令反编译后(部分代码);

 public static synchronized void fun1();
    descriptor: ()V
    // 看这里
    flags: ACC_PUBLIC, ACC_STATIC, ACC_SYNCHRONIZED

  public synchronized void fun2();
    descriptor: ()V
    // 看这里
    flags: ACC_PUBLIC, ACC_SYNCHRONIZED

  public void fun3();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=3, args_size=1
         0: aload_0
         1: dup
         2: astore_1
         // 看这里
         3: monitorenter
         4: aload_1
         // 看这里
         5: monitorexit
         6: goto          14
         9: astore_2
        10: aload_1
         // 看这里
        11: monitorexit
  • 修饰方法:ACC_SYNCHRONIZED标识,会隐式调用到下面两个方法;
  • 修饰代码块:一个monitorenter,两个monitorexit,避免异常未释放锁;

总结:sychronized本质就是对monitor的争夺,在持有重量级锁对象头中,存储了monitor的指针。

基础知识:对象结构

Java对象由三个部分组成;

  1. 对象头:对象年龄,锁标志,Class类型指针和数组长度(可选);
  2. 实例数据:真正存储的有效数据,例如当前的成员变量,包括父类;
  3. 对齐填充:HotSpot VM规定对象起始地址为8字节的整数倍,不够则需要填充;

Mark Word

重中之重:对象锁

JDK 1.6 增加的锁优化流程,之前只有重量级锁。

锁类型

  • non-biasable 无锁且不可偏向
  • biasable 无锁可偏向
  • biased 偏向锁
  • thin lock 轻量级锁
  • fat lock 重量级锁

rebias & revoke

  • bulk rebias(批量重偏向):如果已经偏向t1线程的对象,在t2线程申请锁时撤销偏向后升级为轻量级锁的对象数量达到一定值(20),后续的申请会批量重偏向到t2线程;
  • bulk revoke(批量撤销):在单位时间(25s)内某种Class的对象撤销偏向的次数达到一定值(40),JVM认定该Class竞争激烈,撤销所有关联对象的偏向锁,且新实例也是不可偏向的;

对象初始化

申请加锁

证据第一:动手试试

JVM参数

-XX:+UseBiasedLocking 启用偏向锁,默认启用
-XX:+PrintFlagsFinal 打印JVM所有参数
-XX:BiasedLockingStartupDelay=4000 偏向锁启用延迟时间,默认4秒
-XX:BiasedLockingBulkRebiasThreshold=20 批量重偏向阈值,默认20
-XX:BiasedLockingBulkRevokeThreshold=40 批量撤销阈值,默认40
-XX:BiasedLockingDecayTime=25000

添加依赖

<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.16</version>
</dependency>

统一打印对象头方法;

public static void print(Object flag, Object object) {
    String str = ClassLayout.parseInstance(object).toPrintable();
    System.out.println(flag + ".......................................");
    System.out.println(str);
}

锁升级

public static void main(String[] args) {
    Object init = new Object();
    // non-biasable 不可偏向
    print("init before", init);
    synchronized (init) {
        // thin lock 轻量级锁
        print("init sync", init);
    }
    sleep(4000);
    Object object = new Object();
    // biasable 可偏向模式,默认4S后开启偏向模式
    print("object before", object);
    synchronized (object) {
        // biased 持有偏向锁
        print("object sync", object);
    }
    // biased 偏向锁不会被释放
    print("object after", object);

    Thread t1 = new Thread(() -> {
        synchronized (object) {
            // thin lock 持有轻量级锁,不同线程请求
            print("[t1]object sync", object);
        }
        // non-biasable 不可偏向模式
        print("[t1]object after", object);
    });
    t1.start();
    sleep(100);
    Thread t2 = new Thread(() -> {
        synchronized (object) {
            // thin lock 持有轻量级锁,不同线程请求
            print("[t2]object sync", object);
            sleep(1000);
            // fat lock 重量级锁,下面加锁失败导致
            print("[t2]object sync sleep", object);
        }
    });
    t2.start();
    sleep(500);
    synchronized (object) {
        // fat lock 重量级锁
        print("[main]object sync", object);
    }
    // fat lock 重量级锁不会撤销,线程结束变为不可偏向模式
    print("[main]object after", object);
}

批量重偏向&批量撤销

public static void main(String[] args) throws InterruptedException {
    print("oldPrincipe", new SynchronizedPrincipe());
    int loop = 39;
    List<SynchronizedPrincipe> list = new ArrayList<>();
    for (int i = 0; i < loop; i++) {
        SynchronizedPrincipe principe = new SynchronizedPrincipe();
        list.add(principe);
    }
    for (int thread = 1; thread <= 3; thread++) {
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < list.size(); i++) {
                print(i + 1, list.get(i));
                synchronized (list.get(i)) {
                    // 19: thin lock
                    // 20: biased (Rebias)
                    print(i + 1, list.get(i));
                }
                print(i + 1, list.get(i));
            }
        });
        t1.start();
        sleep(1000);
    }
    SynchronizedPrincipe newPrincipe = new SynchronizedPrincipe();
    // non-biasable (Revoke)
    print("newPrincipe", newPrincipe);
}

参考

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

synchronized底层原理 的相关文章

随机推荐

  • 已知某年和某月,获得该月的周数及每周的始末时间

    最近阿Q在项目开发中遇到一个小问题 后台统计 已知某年和某月 计算该月每周的销量 这就要求我们要获取特定年月的周数以及每周的始末时间来对数据库数据进行筛选 大家一看到这个问题是不是都会想起java的日期类Calendar 然后会调用getA
  • 基于verilog实现2FSK调制解调器

    文章目录 前言 一 调制解调概念 1 2FSK原理 二 硬件设计 1 调制器设计思路 2 解调器设计思路 三 代码 1 顶层 2 F1载波发生模块 3 F2载波发生模块 4 频率计模块 5 测试文件 四 仿真结果 前言 在某些具体情况下 如
  • 【C语言】操作符详解(下篇)

    操作符分类 6 关系操作符 7 逻辑操作符 8 条件操作符 9 逗号表达式 10 下标引用操作符 11 函数调用操作符 12 结构成员访问操作符 13 表达式求值 13 1 隐式类型转换 13 2 算术转换 13 3 操作符的属性 6 关系
  • Android Studio改变.gradle默认的存储位置

    Android studio会将下载的gradle配置文件保存到C盘下的user 用户名 gradle文件下 导致c盘内存减少 改变路径的步骤 第一步 修改 此文件下的idea properties文件 我在修改时 出现了没有修改权限问题
  • 矩阵分析与应用-15-逆矩阵

    逆矩阵的定义与性质 一个n xn矩阵称为非奇异矩阵 若它具有n个线性无关的列向量和n个线性无关的行向量 非奇异矩阵也可以从线性系统的观点出发定义 一线性变换或正方矩阵A称为非奇异的 也就是说若它只对零输入产生零输出 否则 它是奇异的 如果一
  • Android图片加载框架Glide的基本用法

    Android图片加载框架Glide的基本用法 原文链接 http blog csdn net guolin blog article details 53759439 现在Android上的图片加载框架非常成熟 从最早的老牌图片加载框架U
  • 太阳能充电板给锂电池充电电路设计

    目前很多产品都使用了太阳能板给板卡充电 如何进行电路设计呢 确定充电管理芯片 充电管理芯片的目的是 对电池有不同模式的充电 包括涓流充电 恒流充电 恒压充电等 在电池不同的容量下进行不同的模式 才能更好的保护电池 如下是一枚国产芯片的描述
  • 左神算法 基础

    哈希表的简单介绍 1 哈希表在使用层面上可以理解为一种集合结构 2 如果只有key 没有伴随数据value 可以使用HashSet结构 C 中叫UnOrderedSet 3 如果既有key 又有伴随数据value 可以使用HashMap结构
  • Docker镜像的创建方法及Dockerfile案例

    目录 一 基于现有镜像创建 1 创建启动镜像 2 生成新镜像 三 基于Dockerfile创建 1 Dockerfile结构及分层 2 联合文件系统 3 docker镜像加载原理 4 dockerfile操作常用的指令 四 Dockerfi
  • getline函数的用法

    一 getline函数的用法 getline只要一遇到换行符就结束读取操作并返回结果 哪怕一开始输入的是换行符也是如此 C 中有两个getline函数 一个是在string头文件中 定义的是一个全局的函数 函数声明是 istream get
  • 电容元件(五)

    文章目录 一 电容元件 电容器 电容元件 线性时不变电容元件 电容的电压 电流关系 电容的储能和功率 二 电感元件 电感线圈 电感元件定义 线性时不变电感元件 电感的电流电压关系 电感的储能和功率 三 动态电路的方程 动态电路 动态电路的方
  • 基于51单片机的DS18B20测温程序与仿真图

    一 基础介绍 时序介绍就暂不介绍 可以网上搜集资料 二 proteus仿真图 三 程序代码 include
  • 分享3个CPU跑分数据库查询,AMD Inter cpu各项分数查询

    https www cpu monkey com en https us rebusfarm net en tempbench view benchmark https www cgdirector com 一个简单的CPU分数查询网站分享
  • 如何将低质量文件升级为高清文件?(Topaz Video AI 教程)

    好多朋友在处理视频的时候会遇到视频清晰度较低的问题 那么如何将低质量视频转换为高质量视频呢 这里就可以用Topaz Video AI for mac 人工智能视频增强软件 来升级视频质量 使用Topaz Video AI 低质量视频文件升级
  • 学机器人要学什么编程

    学机器人要学什么编程 孩子的学习一直都是家长们十分关心和重视的一件事情 很多的家长在培养孩子的学习方面也可以说是相当的耐心的 就拿现在很多的家长想要孩子去学习机器人编程的课程来说 有的家长对于学机器人要学什么编程并不是很清楚 今天我们就一起
  • ChatGPT不到1分钟生成全部代码,你就说慌不慌吧?

    生成过程视频 如何使用ChatGPT快速生成代码 qq com 如何使用ChatGPT快速生成SpringBoot集成Dubbo的完整案例 1 Dubbo最新版本有哪些新特性 Dubbo最新版本是2 7 9 于2021年6月发布 以下是该版
  • cv2.VideoCapture()从网络摄像头取RTSP流失败的解决办法

    树莓派从网络摄像头取流 需求 问题与现象 分析 总结 需求 将大华的网络摄像头连接到树莓派网口 取出视频进行处理 问题与现象 连接硬件 将树莓派有线网卡的ip固定设置于摄像头的同一网段 将大华给的URL填到VLC里打开 可以播放视频 将大华
  • 【电源之美】DCDC三种工作模式:CCM、DCM、BCM

    DCDC的三种工作模式 CCM连续导通模式 DCM断续导通模式 BCM临界导通模式 CCM Continuous Conduction Mode 连续导通模式 在一个开关周期内 电感电流从不会到0 或者说电感从不 复位
  • 学习 Rust cookbook 之算法篇(algorithm)

    原文作者 suhanyujie 永久链接 https github com suhanyujie rust cookbook note 博客链接 https ishenghuo cnblogs com 学习 Rust cookbook 之算
  • synchronized底层原理

    一探究竟 反编译 三种使用场景 示例代码 public class SynchronizePrincipe public synchronized static void fun1 public synchronized void fun2