Java synchronized锁升级jol过程详解

 更新时间:2020年04月02日 08:37:15   作者:Katsu  
这篇文章主要介绍了Java synchronized锁升级jol过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

jol(java object layout)需要的依赖

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

一。synchronized锁对象的升级(膨胀)过程主要如下:

1.膨胀过程:无锁(锁对象初始化时)-> 偏向锁(有线程请求锁) -> 轻量级锁(多线程轻度竞争)-> 重量级锁(线程过多或长耗时操作,线程自旋过度消耗cpu);

2.jvm默认延时4s自动开启偏向锁(此时为匿名偏向锁,不指向任务线程),可通过-XX:BiasedLockingStartUpDelay=0取消延时;如果不要偏向锁,可通过-XX:-UseBiasedLocking = false来设置

3.锁只能升级,不能降级;偏向锁可以被重置为无锁状态

4.锁对象头记录占用锁的线程信息,但不能主动释放,线程栈同时记录锁的使用信息,当有其他线程(T1)申请已经被占用的锁时,先根据锁对向的信息,找对应线程栈,若线程已结束,则锁对象先被置为无锁状态,再被T1线程占有后置为偏向锁;若线程位结束,则锁状态由当前偏向锁升级为轻量级锁。

5.偏向锁和轻量级锁在用户态维护,重量级锁需要切换到内核态(os)进行维护;

二。锁对象头(markword部分,8字节)使用不同的状态进行表示,64位虚拟机的markword如下所示:

使用jol演示如下:

1.无锁状态

Object object = new Object(); System.out.println("hash: " + object.hashCode()); System.out.println(ClassLayout.parseInstance(object).toPrintable());

header中前8个字节按照平时习惯的从高位到低位的展示为:00000000 00000000 00000000 00111001 10101110 11101101 00101111 00000001

对照上图,最后3位是001,无锁状态,中间31位(0111001 10101110 11101101 00101111)换算成十进制即为上图打印的hash:967765295

2.匿名偏向锁和偏向锁

Thread.sleep(5000); //等待jvm开启偏向锁
    Object o = new Object();
    System.out.println(ClassLayout.parseInstance(o).toPrintable());

    synchronized (o){
      System.out.println(ClassLayout.parseInstance(o).toPrintable());
    }

第一次打印为匿名偏向,第二次偏向锁指向了main线程

注意:用run启动程序,不要用debug,实验的时候,用debug启动,第二次打印直接升级轻量级锁。

3.轻量级锁

public static void main(String[] args) throws InterruptedException {
    Thread.sleep(5000);
    Object o = new Object();
    synchronized (o) {
      System.out.println(ClassLayout.parseInstance(o).toPrintable());
    }
    for (int i = 0; i < 1; i++) {
      Thread t = new Thread(() -> {
        print(o);
      });
      t.start();
    }
  }

  public static void print(Object o) {
    synchronized (o){
      System.out.println(ClassLayout.parseInstance(o).toPrintable());
    }
  }

4.重量级锁

public static void main(String[] args){
    Object o = new Object();
    for (int i = 0; i < 2; i++) {
      Thread t = new Thread(() -> {
        print(o);
      });
      t.start();
    }
  }

  public static void print(Object o) {
    synchronized (o){
      System.out.println(ClassLayout.parseInstance(o).toPrintable());
    }
  }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • Java中静态类型检查是如何进行的实例思路详解

    Java中静态类型检查是如何进行的实例思路详解

    这篇文章主要介绍了Java中静态类型检查是如何进行的实例思路详解的相关资料,需要的朋友可以参考下
    2016-05-05
  • Spring Boot 4.0对于Java开发的影响和前景

    Spring Boot 4.0对于Java开发的影响和前景

    探索Spring Boot 4.0如何彻底革新Java开发,提升效率并开拓未来可能性!别错过这篇紧凑的指南,它带你领略Spring Boot的强大魅力和潜力,准备好了吗?
    2024-02-02
  • java生成缩略图的方法示例

    java生成缩略图的方法示例

    这篇文章主要介绍了java生成缩略图的方法,结合具体实例形式分析了java生成缩略图过程中所涉及的各种常见的图形处理技巧,需要的朋友可以参考下
    2017-03-03
  • MyBatis如何实现多表查询(多对一、一对多)

    MyBatis如何实现多表查询(多对一、一对多)

    这篇文章主要给大家介绍了关于MyBatis如何实现多表查询(多对一、一对多)的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-05-05
  • SpringBoot整合SpringSecurity认证与授权

    SpringBoot整合SpringSecurity认证与授权

    在项目开发中,权限认证是很重要的,尤其是一些管理类的系统,对于权限要求更为严格,本文主要介绍了SpringBoot整合SpringSecurity认证与授权,感兴趣的可以了解一下
    2023-11-11
  • Java编程思想中关于并发的总结

    Java编程思想中关于并发的总结

    在本文中小编给大家整理的是关于Java编程思想中关于并发的总结以及相关实例内容,需要的朋友们参考下。
    2019-09-09
  • Struts2访问Servlet的三种方式

    Struts2访问Servlet的三种方式

    这篇文章主要介绍了Struts2访问Servlet的三种方式,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-06-06
  • Mybatis 数据库连接池的实现示例

    Mybatis 数据库连接池的实现示例

    在Java应用程序中,与数据库的连接是非常昂贵的,因此,当我们使用MyBatis进行数据操作时,需要一个连接池来分配并管理这些连接,本文主要介绍了Mybatis 数据库连接池的实现示例,具有一定的参考价值,感兴趣的可以了解一下
    2023-10-10
  • Java11中基于嵌套关系的访问控制优化详解

    Java11中基于嵌套关系的访问控制优化详解

    Java(和其他语言)通过内部类支持嵌套类,要使其正常工作,需要编译器执行一些技巧,下面这篇文章主要给大家介绍了关于Java11中基于嵌套关系的访问控制优化的相关资料,需要的朋友可以参考下
    2022-01-01
  • java中使用map排序的实例讲解

    java中使用map排序的实例讲解

    在本篇文章里小编给大家整理了一篇关于java中使用map排序的实例讲解内容,有兴趣的朋友们可以学习下。
    2020-12-12

最新评论