当前位置: 首页 > 知识库问答 >
问题:

java - 求助synchronized底层原理,锁升级过程到底是怎么样的?

赫连瀚
2024-05-31

synchronized底层原理,关于无锁、偏向锁、轻量级锁、重量级锁问题

public static void main(String[] args) throws InterruptedException {        //HotSpot 虚拟机在启动后有个 4s 的延迟才会对每个新建的对象开启偏向锁模式        Thread.sleep(5000);        Object obj = new Object();        System.out.println("匿名偏向状态 =====================" + "\n" + ClassLayout.parseInstance(obj).toPrintable());        new Thread(() -> {            synchronized (obj) {                System.out.println(Thread.currentThread().getName() + "获取锁执行中。。。\n"                        + ClassLayout.parseInstance(obj).toPrintable());            }        }, "thread-a").start();                // 这段代码未注释时会出现两种结果:        // 结果1:初始化偏向锁(未偏向)-->偏向锁(线程A)->偏向锁(线程B)        // 结果2:初始化偏向锁(未偏向)-->偏向锁(线程A)->轻量级锁(线程B)->无锁        // 代码注释也会有两种结果:        // 结果1:初始化偏向锁(未偏向)-->偏向锁(线程A)->重量级锁(线程B)->无锁        // 结果2:初始化偏向锁(未偏向)-->重量级锁(线程A)->重量级锁(线程B)->无锁        Thread.sleep(1000);        new Thread(() -> {            synchronized (obj) {                System.out.println(Thread.currentThread().getName() + "获取锁执行中。。。\n"                        + ClassLayout.parseInstance(obj).toPrintable());            }        }, "thread-b").start();        // 睡眠5s后        Thread.sleep(5000);        System.out.println(Thread.currentThread().getName() + ClassLayout.parseInstance(obj).toPrintable());    }

image.png
image.png

    Thread.sleep(1000);    // 这段代码未注释时会出现两种结果:    // 结果1:初始化偏向锁(未偏向)-->偏向锁(线程A)->偏向锁(线程B)    // 结果2:初始化偏向锁(未偏向)-->偏向锁(线程A)->轻量级锁(线程B)->无锁    // 代码注释也会有两种结果:    // 结果1:初始化偏向锁(未偏向)-->偏向锁(线程A)->重量级锁(线程B)->无锁    // 结果2:初始化偏向锁(未偏向)-->重量级锁(线程A)->重量级锁(线程B)->无锁**以上代码JDK版本1.8**看了网上很多视频和文章的分析,总结下来是大多数讲的没那么深,而且有一些细节地方每篇文章可能分析的都不一样,参考那些技术的分析还是没有弄懂为什么会产生这几种不同的结果,底层的锁升级逻辑到底是怎样的呢,有没有大佬帮忙仔细分析下呢,如果能带着一起看源码那最好了......    

共有1个答案

幸弘扬
2024-05-31
                匿名偏向状态 =====================                java.lang.Object object internals: OFFSET  SIZE   TYPE DESCRIPTION                               VALUE      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)      8     4        (object header)                           58 0d 00 00 (01011000 00001101 00000000 00000000) (3416)     12     4        (loss due to the next object alignment)Instance size: 16 bytesSpace losses: 0 bytes internal + 4 bytes external = 4 bytes total                        thread-a获取锁执行中。。。                        java.lang.Object object internals: OFFSET  SIZE   TYPE DESCRIPTION                               VALUE      0     4        (object header)                           d0 f3 7f 2b (11010000 11110011 01111111 00101011) (729805776)      4     4        (object header)                           e3 00 00 00 (11100011 00000000 00000000 00000000) (227)      8     4        (object header)                           58 0d 00 00 (01011000 00001101 00000000 00000000) (3416)     12     4        (loss due to the next object alignment)Instance size: 16 bytesSpace losses: 0 bytes internal + 4 bytes external = 4 bytes total                        thread-b获取锁执行中。。。                        java.lang.Object object internals: OFFSET  SIZE   TYPE DESCRIPTION                               VALUE      0     4        (object header)                           40 f0 2f 2b (01000000 11110000 00101111 00101011) (724561984)      4     4        (object header)                           e3 00 00 00 (11100011 00000000 00000000 00000000) (227)      8     4        (object header)                           58 0d 00 00 (01011000 00001101 00000000 00000000) (3416)     12     4        (loss due to the next object alignment)Instance size: 16 bytesSpace losses: 0 bytes internal + 4 bytes external = 4 bytes totalmainjava.lang.Object object internals: OFFSET  SIZE   TYPE DESCRIPTION                               VALUE      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)      8     4        (object header)                           58 0d 00 00 (01011000 00001101 00000000 00000000) (3416)     12     4        (loss due to the next object alignment)Instance size: 16 bytesSpace losses: 0 bytes internal + 4 bytes external = 4 bytes total

我运行几次都是这个样子,高版本的jvm 已经废弃了偏向锁。所以结果比较符合预期,依次为 01,00,00,01 无锁,轻量级锁,轻量级锁,无锁。这样,就很符合预期了,要不就别纠结偏向锁了吧。

 类似资料:
  • 主要内容:一、synchronized的使用方式,二、synchronized锁的原理,三、synchronized锁的优化,四、Lock锁与synchronized一、synchronized的使用方式 在语法上,要使用synchronized关键字,需要把任意一个非null对象作为"锁"对象,也就是需要一个对象监视器(Object Monitor)。总的来说有三种用法: 1.1 作用在实例方法 修饰实例方法,相当于对当前实例对象this加锁,this作为对象监视器。 1.2 作用在静态方法

  • 主要内容:一、synchronized的使用方式,二、synchronized锁的原理,三、synchronized锁的优化,四、Lock锁与synchronized一、synchronized的使用方式 在语法上,要使用synchronized关键字,需要把任意一个非null对象作为"锁"对象,也就是需要一个对象监视器(Object Monitor)。总的来说有三种用法: 1.1 作用在实例方法 修饰实例方法,相当于对当前实例对象this加锁,this作为对象监视器。 1.2 作用在静态方法

  • synchronized 锁升级原理:在锁对象的对象头里面有一个 threadid 字段,在第一次访问的时候 threadid 为空,jvm 让其持有偏向锁,并将 threadid 设置为其线程 id,再次进入的时候会先判断 threadid 是否与其线程 id 一致,如果一致则可以直接使用此对象,如果不一致,则升级偏向锁为轻量级锁,通过自旋循环一定次数来获取锁,执行一定次数之后,如果还没有正常获

  • 本文向大家介绍多线程中 synchronized 锁升级的原理是什么?相关面试题,主要包含被问及多线程中 synchronized 锁升级的原理是什么?时的应答技巧和注意事项,需要的朋友参考一下 synchronized 锁升级原理:在锁对象的对象头里面有一个 threadid 字段,在第一次访问的时候 threadid 为空,jvm 让其持有偏向锁,并将 threadid 设置为其线程 id,再

  • 本文向大家介绍讲一下 synchronized 关键字的底层原理 ?相关面试题,主要包含被问及讲一下 synchronized 关键字的底层原理 ?时的应答技巧和注意事项,需要的朋友参考一下 synchronized 是由一对 monitorenter/monitorexit 指令实现的,monitor 对象是同步的基本实现单元。 在 Java 6 之前,monitor 的实现完全是依靠操作系统内

  • 主要内容:一、写在前面,二、ReentrantLock和AQS的关系,三、ReentrantLock加锁和释放锁的底层原理,四、总结一、写在前面 上一篇文章聊了一下java并发中常用的原子类的原理和Java 8的优化,具体请参见文章:《为什么程序员招聘都要5年经验起?因为他们懂Java8底层优化!》。 这篇文章,我们来聊聊面试的时候比较有杀伤力的一个问题:聊聊你对AQS的理解? 之前有同学反馈,去互联网公司面试,面试官聊到并发时就问到了这个问题。当时那位同学内心估计受到了一万点伤害。。。 因为首