【JVM】synchronized锁升级的过程

这篇具有很好参考价值的文章主要介绍了【JVM】synchronized锁升级的过程。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

如何从无锁状态到偏向锁状态:

偏向锁升级为轻量级锁:

轻量级锁到自旋锁的状态:

自旋锁升级为重量级锁:

下面是自旋锁升级到重量级锁的过程:

重量级锁的特点如下:


synchronized锁分为三种状态——偏向锁、轻量级锁、重量级锁

如何从无锁状态到偏向锁状态:

        当一个线程访问被synchronized修饰的代码块的时候,并获取对象的锁时,会在对象头中的Mark Word中记录该线程的ID,这就叫做偏向锁

        如果对象的Mark Word中的记录的线程ID为0,表示当前没有线程获取锁,则将该线程的ID记录到Mark Word当中,并将对象头指向偏向锁。

偏向锁升级为轻量级锁:

  • 当其他线程尝试获取一个对象的锁的时候,JVM发现对象头指向的线程ID和当前线程ID不一致的时候,会尝试将偏向锁升级为轻量级锁。
  • JVM也会在Mark Word中分配空间存储锁记录(锁记录包含指针、标志位等信息)
  • 然后JVM会使用CAS(Compare and Swap)操作尝试将对象头中的偏向锁替换为指向锁记录的指针,并将线程ID记录到锁记录当中
  • 如果CAS操作成功,表示锁升级成功,当前线程进入临界区指向代码;如果失败,则说明有其他线程竞争,可能进一步升级为重量级锁

轻量级锁到自旋锁的状态:

  1. 初始状态:假设有两个线程A和B,线程A先获取到了对象obj的轻量级锁,并且正在执行临界区代码。
  2. 竞争锁:线程B也想要获取对象obj的锁,但发现轻量级锁已经被线程A获取了,此时线程B会进入自旋锁状态。
  3. 自旋锁等待:线程B进入自旋锁状态后,会进行一定次数的自旋(即循环重试),不断检查轻量级锁的标记是否被线程A释放。
  4. 自旋锁优化:在自旋锁状态下,如果线程A在很短的时间内释放了轻量级锁,线程B可以立即获取到锁而无需进入阻塞状态。这种情况下,自旋锁避免了线程上下文切换的开销,提高了性能。
  5. 自旋锁等待超时:如果线程B在自旋一定次数后仍然无法获取到锁,就会认为竞争激烈,并且有其他线程执行临界区代码的可能性不大。此时,线程B会放弃自旋锁而进入阻塞状态,让出CPU执行权,等待锁释放。
  6. 自旋锁的优势:自旋锁在临界区代码执行时间短、线程竞争不激烈的情况下可以提高性能,因为避免了线程上下文切换。但如果临界区代码执行时间长,或者线程竞争激烈,使用自旋锁可能会浪费CPU资源。

自旋锁升级为重量级锁:

        当一个线程在自旋锁状态下无法获取到锁时,它会升级到重量级锁。重量级锁是一种阻塞锁,它会导致线程进入阻塞状态并释放CPU的执行权。

下面是自旋锁升级到重量级锁的过程:

  1. 自旋锁等待:假设有两个线程A和B,线程A持有了对象obj的自旋锁,并且正在执行临界区代码。线程B尝试获取锁但失败,进入自旋状态。
  2. 自旋锁等待超时:线程B在经过一定次数的自旋后,仍然无法获取到锁。此时,线程B会放弃自旋锁,并将自己挂起,进入阻塞状态。
  3. 锁升级:线程B进入阻塞状态后,JVM会将锁升级为重量级锁。重量级锁的特点是会导致线程进入阻塞状态,并且释放CPU的执行权。
  4. 线程阻塞:线程B被阻塞后,它不会再去尝试获取锁,直到锁被释放。此时,线程B会进入一个等待唤醒的状态。
  5. 锁释放:当线程A执行完临界区代码后,会释放锁。此时,JVM会选择一个阻塞的线程(例如线程B)唤醒,使其重新尝试获取锁。
  6. 线程唤醒:被唤醒的线程(例如线程B)会从阻塞状态中恢复,并且开始重新尝试获取锁。

重量级锁的特点如下:

  • 高开销:使用重量级锁的线程会进入阻塞状态,这样会导致线程上下文切换的开销,影响性能。
  • 公平性:重量级锁通常是公平的,即等待时间最长的线程会被优先唤醒,以保证公平性。
  • 线程阻塞:获取重量级锁失败的线程会进入阻塞状态,不会消耗CPU资源,等待锁的释放。
  • 粒度较大:重量级锁对应整个对象而不是对象的某个部分,因此在多线程竞争情况下,会导致其他线程也无法访问对象。

        需要注意的是,升级到重量级锁的过程并非是一成不变的,具体实现可能会有不同的策略和优化。锁的具体行为和性能表现还取决于文章来源地址https://www.toymoban.com/news/detail-701704.html

到了这里,关于【JVM】synchronized锁升级的过程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • JVM类加载过程

    类加载Class类型的文件主要三步: 加载-链接-初始化 。链接过程又可以分为三步: 验证-准备-解析 。 将类的字节码载入方法区中,内部采用 C++ 的 instanceKlass 描述 java 类,它的重要 field 有: _java_mirror 即 java 的类镜像,例如对 String 来说,就是 String.class,作用是把 klass 暴 露

    2023年04月23日
    浏览(39)
  • 【JVM】类装载的执行过程

    类装载总共分为7个过程,分别是 加载,验证,准备、解析、初始化、使用、卸载 1.加载 将 类的字节码文件 加载到 内存 (元空间)中。这一步会创建一个与被加载类对应的Class对象。 通过类的全名,获取类的二进制数据流。 解析类的二进制数据流为方法区内的数据结构(

    2024年02月13日
    浏览(33)
  • JVM中类加载的过程

    把.class文件加载到内存中,得到类对象的过程。 找到.class文件,读取文件内容 验证找到的文件是否为一个.class文件,.class文件有明确的数据格式 给类对象分配空间。 注意这个空间是未初始化的空间,内存空间中的数据是全0的。 字符串常量池中的符号引用替换为直接引用。

    2024年02月16日
    浏览(38)
  • JVM系列(5)——类加载过程

    加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)和卸载(Unloading)。 看图: 1、加载 类加载过程的第一步,主要完成下面 3 件事情: 1、通过全类名获取定义此类的二进制字节流。 2、将字节流所代表的静态存储

    2024年02月16日
    浏览(39)
  • JVM 分代垃圾回收过程

    堆空间划分了代: 年轻代(Young Generation)分为 eden 和 Survivor 两个区,Survivor 又分为2个均等的区,S0 和 S1。 首先,新对象都分配到年轻代的 eden 空间,Survivor 刚开始是空的。 当 eden 满了以后,minor gc 就被触发了。 还被引用的对象被移到第一个 survivor 空间,然后把整个 ede

    2024年02月06日
    浏览(65)
  • JVM面试题-JVM对象的创建过程、内存分配、内存布局、访问定位等问题详解

    内存分配的两种方式 指针碰撞 适用场合:堆内存 规整 (即没有内存碎片)的情况下。 原理:用过的内存全部整合到一边,没有用过的内存放在另一边,中间有一个分界指针,只需要向着没用过的内存方向将该指针移动对象内存大小位置即可。 使用该分配方式的GC收集器:

    2024年02月08日
    浏览(53)
  • [JVM] Java类的加载过程

    在Java中,类的加载是指在程序运行时将类的二进制数据加载到内存中,并转化为可以被JVM执行的形式的过程。类的加载过程主要包括以下几个步骤: 加载 (Loading):通过类的全限定名,使用类加载器将类的二进制数据加载到JVM中。类加载器会根据类的名称找到对应的字节码

    2024年01月16日
    浏览(36)
  • JVM源码剖析之线程的创建过程

    对于Java线程的创建这个话题,似乎已经被\\\"八股文\\\"带偏~ 大部分Java程序员从\\\"八股文\\\"得知创建Java线程有N种方式,比如new Thread、new Runnable、Callable、线程池等等~ 而笔者写下这篇文章的目的是让大家从JVM源码的层面知道创建一个Java线程的方式。 版本信息: jdk版本:jdk8u40 从

    2024年02月07日
    浏览(48)
  • JVM源码剖析之Java对象创建过程

    关于 \\\"Java的对象创建\\\" 这个话题分布在各种论坛、各种帖子,文章的水平参差不齐。并且大部分仅仅是总结 \\\"面试宝典\\\" 的流程,小部分就是copy其他帖子,极少能看到拿源码作为论证。所以特意写下这篇文章。 版本信息如下: 首先把总结图放在这。接下来分析源码~  用一个

    2024年02月12日
    浏览(48)
  • JVM运行时区域——对象创建内存分配过程

            新创建的对象 , 都存放在伊甸园区域 ,当垃圾回收时,将伊甸园区域的垃圾数据销毁,然后将存活的对象转移到幸存者0区域,之后创建的新的对象还是存放在伊甸园区域,等到再次垃圾回收后,将伊甸园区域和幸存者0区域中存活的对象一起转移到幸存者1区域中

    2024年02月15日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包