当前位置: 首页 > article >正文

Synchronized锁升级之无锁和偏向锁

为了优化synchronized锁的效率,在JDK1.6中,HotsPot虚拟机开发团队提出了锁升级的概念,包括偏向锁、轻量级锁、重量级锁,锁的升级值的是 无锁态 >> 偏向锁 >> 轻量级锁 >> 重量级锁

synchronized同步锁相关信息保存在锁对象的对象同中的Mark Word中,锁升级功能主要是依赖Mark Word中锁的标准为何是否偏向锁来实现的
在这里插入图片描述

从上图我们可以看到,无锁态对应的锁标志位位 01,是否偏向锁标志位 0,下面通过两个简单的Java case来演示无锁态和轻量级锁

因为要查看代码运行时的内存布局分析,所以在构建的maven工程中需要加入如下依赖

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

1.无锁态

下面用一段代码来演示什么是无锁态

  1. Java code
public class Main {
    public static void main(String[] args) {
        Object objLock = new Object();
        // 需要注意,只有调用了hashCode(),对象头中的MarkWord才会保存对应的hashCode值,否则全部是0
        System.out.println("10进制: " + objLock.hashCode());
        System.out.println("2进制: " + Integer.toBinaryString(objLock.hashCode()));
        System.out.println("16进制: " + Integer.toHexString(objLock.hashCode()));
        System.out.println(ClassLayout.parseInstance(objLock).toPrintable());
    }
}
  1. 代码运行时输出的结果
    在这里插入图片描述

  2. 分析

Mark Word对象头共站8个字符,共64位,也就是上图中的 1 ~ 8,从后往前拼起来

00000000 00000000 00000000 01100111 01110011 00100111 10110110 00000001

Mark Word在64位JVM中内部结构中

  1. 红色字体部分:25位,不使用
  2. 蓝色字体部分:31位,表示对象的hashCode(可以看到与代码输出结构中的二进制hashCode是一样的)
  3. 橙色字体部分:1位,不使用
  4. 绿色字体部分:4位,表示对象的分代年龄(对象的最大分代年龄是15,占用的四个字节的最大是 1111 ,将其换成10进制即是 15)
  5. 紫色字体部分:1位,偏向锁标准为(0:不是,1:是)
  6. 黄色字体部分:2位,锁的标志位,按照上图中的这里是无锁态(001无锁态,101偏向锁,000轻量级锁,010重量级锁,011GC标识)

2.偏向锁

注意事项

偏向锁的启用时机,偏向锁在程序运行时需要进行 4s 的加载,如果程序在运行时,线程还没有去访问锁前程序的运行时间已经超过了4s,那么此时这把锁将会从无锁态升级到偏向锁

2.1.偏向锁的原理

  1. 在偏向锁第一次被线程拥有的时候,在偏向锁的Mark Word中,有一块区域用来记录偏向锁的ID,如下图所示
    在这里插入图片描述

  2. 偏向锁的好处是什么?

    1. 假设现在的锁对象已经是一个偏向锁,偏向锁它会偏向于第一个获取锁的线程,并且在锁对象的Mark Word中会将该线程的线程ID保存起来,当该线程再来访问锁的时候,会先判断当前访问的线程ID是否是Mark Word中记录的线程ID,如果是将会不进行加锁,该线程直接执行同步块中的代码,这样省去了CAS去更新对象头的操作,提升了锁的性能
  3. 偏向锁再次进入同步代码块,如果保证不需要再次加锁?

2.2.偏向锁的撤销

注意事项

偏向锁只有遇到其他线程尝试竞争偏向锁时,持有偏向锁的线程才会释放锁,线程不会主动释放偏向锁

在大部分情况下,锁都是被同一个线程获取到的,持有偏向锁的线程不会主动释放锁。那么大部分情况下不会涉及到偏向锁的撤销,当有另外的线程尝试竞争偏向锁的时候,这个时候才会涉及偏向锁的撤销流程

暂时无法在飞书文档外展示此内容

2.3.Java case

public class Main {
    public static void main(String[] args) throws InterruptedException {
        // 在这里sleep 5s,等待偏向锁加载成功
        Thread.sleep(6000);
        Object objLock = new Object();
        synchronized (objLock){
            System.out.println(ClassLayout.parseInstance(objLock).toPrintable());
        }
    }
}

在这里插入图片描述


http://www.kler.cn/a/4885.html

相关文章:

  • 【计算机视觉】COCO Caption数据集简单介绍
  • 032:cesium修改默认地图源,动态指定地图
  • Redis7笔记(正在更新中)
  • 【华为OD机试 2023最新 】 优选核酸检测点(C++)
  • 优思学院|平衡计分卡是什么?
  • 网站流量飙升背后:外贸企业谷歌SEO优化实战经验分享
  • Prometheus监控实战系列二十五: Thanos介绍
  • Linux 监控进程创建行为
  • Java设计模式-4、适配器模式
  • 【Hydro】龙格-库塔方法的公式推导
  • ChatGPT背后有哪些关键技术?CSIG企业行带你一探究竟
  • PyTorch 深度学习实战 | 基于生成式对抗网络生成动漫人物
  • JavaScript中bind的用法
  • STM32基于STM32CubeMX DMA + EXTI读取DS1307数据
  • 人大金仓数据库CentOS7安装简述
  • Windows7操作系统
  • 电脑图片压缩到200k以内怎么办?怎么让图片小于200kb?
  • 蓝桥杯--最少刷题数--java
  • 【Flutter 问题系列第 76 篇】在 Flutter 中 Builder 组件的作用以及如何解决 Scaffold.of 找不到上下文问题的解决文案
  • 【16】核心易中期刊推荐——机器学习模式识别