资讯详情 JDK1.6锁升级机制全解析
📅 2026/10/7 2:48:52
在Java后端的面试环节, 锁升级机制不仅是并发编程里最难理解的一部分, 也是中级和高级工程师岗位面试时肯定会问到的重点内容。好多开发者只是表面上知道有个“重量级锁”的说法, 但真正不知道JDK1.6版本以后对它做了哪些优化, 也就是不了解它引入了偏向锁与轻量级锁这一套能让系统自适应地实现锁升级的方案。这些开发者还更没法把锁升级具体会在什么情况下被触发、它底层的运行原理到底是什么, 以及它在不同阶段之间的具体差异解释清楚。这篇文章是从最基本的底层实现层面开始进行分析的, 把锁升级那个完整的流程给拆开来看一看, 这个流程里面包含了从偏向锁变成轻量级锁接着再变成重量级锁这样的过程。文章又把大家在面试时候经常会碰到的那些考点, 还有在实际工作当中会用到的各种场景给结合了起来, 目的是帮助你非常彻底地把锁升级的这个机制给弄明白、给理解透。这样你就能很轻松地应对面试官提出来的各种关于并发相关的问题和追问了同时也可以让你在回答问题的时候避开那些容易出错的误区。锁升级的核心背景在JDK1.6之前, 那个东西被叫做“重量级锁”。其底层是依赖操作系统的互斥锁Mutex Lock实现的。每次获取锁和释放锁的时候, 都会切换用户态和内核态。这个性能开销是非常大的。而在实际开发的场景里。当咱们有多线程并发访问共享资源的时候。“同一时刻只有一个线程竞争锁”。“线程持有锁的时间很短”。还有“锁竞争不激烈”。这些情况才是常态。为了解决掉重量级锁那个性能上面的问题, JDK1.6这个版本, 进行了一个重大的这种优化动作。它里头引入了偏向锁和轻量级锁这两个东西。这样就形成了一整个流程, 这个流程叫作“偏向锁→轻量级锁→重量级锁”的这样一种自适应的一个升级过程。它的核心里的这样一个设计思路是啥样的? 它是根据锁竞争的这个激烈程度来做事的。它会动态地去切换这个锁的级别。竞争越激烈的时候, 锁的级别就会变高一点。锁级别要是高了, 那开销自然也就变得比较大了。反过来讲, 如果竞争的情况比较平缓了一点, 锁的级别就可以降低下去。锁级别低了, 性能方面的表现就会变得更优一些。这样一来, 最终达到的效果是什么? 就是实现了一种平衡。这种平衡是在性能的这种体验和安全性保证之间做的一种平衡。需要补充的是在面试过程中经常被问到的那个高频问题, 也就是那个锁的对象具体是指什么呢? 它指的是对象头。因为每一个Java对象都包含着对象头这个对象头里面存储着包括锁状态、哈希码以及GC年龄等等在内的这些多种信息。所谓锁升级的本质上来看就是在修改位于对象头里面的那些锁状态标记。至于不同级别锁来说它们的对象头结构也是存在不同之处的。而这种差异恰恰是锁升级得以实现的底层基础所在。锁升级完整流程锁升级的核心逻辑是“从低开销到高开销”。这个过程的意思是, 先使用低级别的锁。只有当事务出现的情况导致低级别锁满足不了需求的时候, 才可能会升级为更高级别的锁。比如, 出现了锁竞争这种现象, 就是一种典型的情况。这种升级过程在全程是不可逆的。也就是说, 一旦锁被升级为重量级锁, 就绝对不会再降级为轻量级锁或者偏向锁了。下面我们会对各阶段进行详细解析。在解析过程中, 会结合底层原理还有面试重点这两个方面。1. 初始状态是指无锁的状态, 这个状态出现的时候是对象刚刚被创建出来的时刻。当一个Java对象刚被创建的时候, 它这个对象头里面的锁状态会处于无锁的这个状况。在这个阶段, 没有任何线程持有该对象的锁, 同时也没有任何线程对这把锁进行竞争。在该对象头的内部空间中, 会存储有关于对象的哈希码、还有GC分代年龄这一类的信息。在锁标记位这里, 其数值为01, 这代表着无锁或者偏向锁的标志状态, 而偏向锁标志位则会被设置为0, 以此表示当前处于无锁的情况。场景是对象刚刚被创建出来, 并且还没有被任何一个线程拿来当作锁对象去使用, 就比如那些没有被修饰符标记的对象情况。2. 第一阶段是偏向锁, 这在不存在竞争的场合使用, 能够发挥出最优良的性能表现。偏向锁是JDK1.6这个版本引入的, 它被认为是最轻量级的一种锁。它的核心适用场景主要是针对一个线程反复获取和释放同一把锁的情况发生的时候, 在这种情况里完全不存在任何锁竞争的现象, 所以偏向锁就会倾向于让当前这个线程去持有锁, 目的是为了减少锁在获取阶段以及在释放阶段的开销费用, 具体的表现就是不需要再进行用户态和内核态之间的切换操作了。1偏向锁的核心原理当第一个线程拿到锁, 它就会把对象头里面的“偏向锁标志位”改成1, “锁标记位”就保持在01的状态, 顺便把当前这个线程的身份ID存到对象头里, 这个东西被叫做“偏向线程ID”, 从那以后, 这个线程再去拿锁的时候, 它就只要看看对象头里面存的那个偏向线程ID是不是自己, 如果发现是自己, 那就直接就把锁给拿下了, 完全不需要做多余的什么事情, 也不用搞什么CAS比较, 更不用去阻塞等待, 这样的性能差不多就和没加锁时候的是一样的。关于底层优化的内容, 偏向锁的核心逻辑在于它做了一个假设, 认为在实际运行中只会有一个线程去竞争这把锁。正是因为有了这个假设, 程序就能够避免执行轻量级锁所必要的CAS操作, 同时也省去了重量级锁在需要进行的内核态切换步骤。这一系列做法的最终目的, 是为了把使用锁所带来的开销降到最低程度。2偏向锁的触发条件① 情况是这样的, 只有一个线程获取了锁, 没有其他任何线程进行竞争。线程持有锁的时间比较长, 并且反复获取锁以及释放锁, 比如在一个单线程的循环环境中不断地执行那些需要同步处理的代码块。③在JDK1.6以及更高版本中, 偏向锁功能是默认开启的, 如果用户需要通过特定的方式关闭该功能, 可以借助于JVM参数-XX:-来达成这一目的。3偏向锁会被撤销, 这个情况是在特定的条件被满足时触发的。偏向锁只有在当出现锁竞争的情况之下, 才会被进行撤销处理, 这一动作同时会触发锁升级成为轻量级锁, 常见的导致其被撤销的场景包括:① 第二个线程试图来获取同一把锁, 这时候就会产生锁的竞争情况, 因为偏向锁已经没有办法满足需求了。那个拿着偏向锁的线程, 在把同步里的代码段全部执行结束以后, 就把锁给释放掉了, 接着呢, 有别的线程跑过来试着要去拿到这个锁。当那个持有偏向锁的线程遭遇到了中断或者被阻塞的时候。撤销这个过程的步骤是这样的, 它会先去暂停那个手里握着偏向锁的线程, 这个过程会伴随着短暂的STW, 目的是让系统检查一下这个线程到底还在不在占有着锁, 要是发现它已经先把锁给释放掉了, 那就会再把对象的头部内容改回到没有锁的状态了, 或者是把这个状态升级为轻量级锁也行但如果发现它现在还在继续持有这把锁的话, 那就比较直接了, 干脆就直接把这个状态升级为轻量级锁好了。3. 第二阶段, 也就是轻量级锁阶段, 这个情况适用于竞争程度比较轻微的场景。当多个线程之间交替地来获取同一把锁的时候, 这种轻度竞争的场景下并不会出现线程阻塞的现象, 一旦这种情况发生, 之前的偏向锁就会经历一个被撤销的过程, 并且随之而来的结果是它升级成了轻量级锁。轻量级锁这个机制它所适用的核心场景是什么呢?其实就是锁的竞争并不是非常强烈的时刻, 或者是不同的线程在交替执行一些同步代码片段的时刻。从它的底层实现原理来说, 它是靠CAS操作来完成的, 在整个过程中完全没有必要去进行一次从用户态到内核态的那种切换操作, 正因如此, 它的整体性能表现是明显优于更为沉重的重量级锁的。1轻量级锁的核心原理在获取轻量级锁的这个操作里, 线程首先会把自己的栈帧弄出来搞事情, 然后在里面创建出一个专门叫作Lock的东西, 这个名字就是锁记录, 接着就是把那个锁对象自己的头部的信息原封不动地拷贝一份塞进去, 这部分信息包括的就是在无锁的状态下才有的哈希码, 还有那些锁的标志位啊之类的东西。线程会执行CAS操作, 这种操作能把对象头中的“锁标记位”从01修改为00, 这里的01指的是无锁或者偏向锁的状态, 而00指的是轻量级锁的状态, 紧接着, 这个线程还会把对象头中的“指针”指向自己栈帧里面的那个锁记录。如果CAS操作成功, 这就意味着该线程已经获取到了轻量级锁, 然后就可以接着往下执行同步代码块了。如果 CAS 操作没有成功, 这说明另外有线程正在争夺锁, 也就是出现了轻度竞争的情况, 这时候当前线程就会通过自旋, 去反复尝试获取 CAS 来得到锁, 这样就能够避免陷入阻塞的状态, 只不过自旋的次数是有上限的, 默认值是十个。2所谓轻量级锁, 它被激活以及启动的具体条件和前置要求具体是哪些。偏向锁被撤销了, 因为出现了多个线程去竞争同一把锁。在锁竞争的情况不够激烈的场景之下, 各个线程交替着去执行那些同步的代码片段, 并不会出现某个线程长时间地被阻塞在等待状态的现象。第三个条件是指, 自旋的次数并没有能够达到那个上限值, 至于如何来调整这个具体的自旋次数, 你可以通过JVM参数里面的-XX:这样的方式来进行设置和调整。3轻量级的锁在进行膨胀也就是升级的时候需要满足触发条件。当那个轻量的锁自旋的次数到了最高的限额, 或者出现了多个线程同时在争抢同一把锁这个叫做重度竞争的情况, 导致靠着自旋的办法还是没法拿到这把锁的时候, 它就会膨胀变成一个重的锁。在这样的时候, 线程就不再反复地自旋去看了, 而是直接变成被阻塞的状态, 这样做是为了防止因为一直自旋而消耗掉了过多的CPU资源。可以补充一些在面试中经常会被问到的重点: 关于轻量级锁自旋这个优化手段, 它最本质的思路是什么呢? 其实就是通过消耗CPU的时间, 来避免让线程进入阻塞状态, 从而减少线程阻塞所带来的开销。这种方式比较适用于那些锁被占用的时间特别短, 并且竞争情况不是很激烈的场景。但是假如锁被持有的时间很长, 那么持续进行自旋就会浪费非常多的CPU资源, 在这种情形下把锁升级为重量级锁是更合理的做法。4. 到了第三个阶段, 也就是重量级锁, 通常是在竞争情况非常严重的场景中才会出现。重量级锁其实是最高级别的一种锁, 它的底层是依赖于操作系统那边的互斥锁Mutex Lock来做的, 它的核心适用场景嘛, 就是锁竞争特别激烈, 有好多个线程都在同时抢同一把锁, 而且持有这把锁的时间还挺长的, 在这样的情况下, 如果一个线程没能拿到锁, 那它就直接进入阻塞状态了, 得一直等到那把锁释放出来才行, 这时候虽然性能方面的开销是最大的, 但是它的安全性却是最高的。1重量级锁这个概念, 它的主要原理或者说核心内容, 其实是这样的。当轻量级锁发生膨胀, 进而转变为重量级锁的时候, 系统会将对象头里面的那个锁标记位的数值修改为10, 这个数值代表的就是重量级锁的状态, 与此同时还会让对象头的指针直接指向操作系统层面上的互斥锁。② 线程在获取重量级锁的时候, 如果发现锁已经被其他的线程给持有了, 那么当前的这个线程就会被操作系统挂起, 也就是进入阻塞的状态, 然后被放到锁的等待队列里, 这也被称为阻塞队列, 这样的话就不再用CPU的资源了。③, 持有重量级锁的线程会释放锁, 并且会唤醒等待队列中的一个线程, 被唤醒的这个线程会重新尝试去获取该锁。2重量级锁这个概念所具备的核心特点, 是需要被记下来的内容, 并且在面试中一定会被问到。开销是比较大的, 因为每次都需要获取锁以及释放锁, 而在这个过程中, 会发生用户态到内核态, 还有从内核态到用户态的操作系统级别的切换, 这个性能是远远低于偏向锁的性能和轻量级锁的性能的。② 不具备自旋特性: 线程在尝试获取锁且发现失败的情况下, 会直接转为阻塞状态, 这种做法旨在防止因为进行无意义的自旋轮询操作而产生对CPU运算资源的过度消耗。不可逆的意思是说, 一旦锁升级成了重量级锁这个状态, 它是不会在后来退化成轻量级锁, 或者是偏向锁的, 哪怕后来的锁竞争情况变得缓和了它也不会再降回去了。锁升级完整流程总结面试必背状态先是无锁, 然后是偏向锁, 这种时候没有竞争, 一个线程在单线程里反复地持有, 接下来到了轻量级锁, 这时有轻度竞争, 线程是交替的, 靠自旋来获取, 最后发展到重量级锁, 这时候竞争激烈到了重度, 线程被阻塞, 依赖于操作系统的互斥锁, 整个过程是不可逆的, 是按照锁竞争的激烈程度来动态升级的。记忆的方法非常简单, 就是当只有一个线程并且没有发生竞争的情况时, 会变成偏向锁, 而当有多个线程进行交替访问的时候, 会变成轻量级锁, 最后当多个线程同时发生竞争的时候, 才会变成重量级锁。咱们来看看不同级别的锁之间, 核心上的那些差别是怎么对比的。在求职面试的过程当中, 考官经常会问出关于偏向锁、轻量级锁还有重量级锁它们之间的区别是什么这个问题, 对于这个问题的考察, 核心对比的维度包括了底层的实现方式是什么样的、适用于什么样的实际场景、以及性能上的开销有多大这些方面, 在下面这个表格里面清晰地进行了区分, 可以直接进行背诵, 这样应对起来之后面试官接着提出的那些追问, 就完全没有问题。对比维度偏向锁轻量级锁重量级锁底层实现对象头这个部分里面所存储的内容是偏向线程的ID, 并且不存在关于CAS操作的情况。采取比较并交换操作与自旋机制相结合的方式, 并且利用基于线程栈帧所实现的锁记录这一技术方案来保障数据的一致性。在操作系统的运行过程里, 当涉及到了互斥锁这种被称为Mutex Lock的机制的时候, 通常就需要发生内核态的那种切换行为。锁标记位当前状态是01, 这里的意思是偏向锁标志位的值为1。0010适用场景就是在一个线程里面反复地拿着锁, 但是没有任何争抢的情况存在。多个线程交替地去持有锁, 这种状况属于轻度的竞争。多线程同时进行竞争锁的操作, 存在着重度竞争的情况。性能开销最低几乎没有开销, 不需要使用CAS, 也不会导致阻塞中等强度涉及CAS和自旋, 但不涉及内核态的切换这种情况属于最严重的层级, 具体表现是内核态发生了频繁切换, 同时线程处于阻塞状态。就是线程当前的状态。无阻塞线程正常执行自旋等待这种方式, 它的特点是不对线程产生阻塞作用。进程被阻塞或者是处于挂起的状态, 接着就是去等待被唤醒。是否可逆这种情况是可以被撤销掉的, 随后它会升级为轻量级的锁状态。可以膨胀, 也就是说它会被升级为重量级锁。不可逆无法降级面试当中那些经常会被提到的高频考点, 重点在于对锁升级相关的一些关键性问题进行梳理和总结。下面所要说的这些问题, 是面试官在考核锁升级这一专题时, 最频繁会追问的那些关键点。请你结合这些底层原理去准备按照以下标准答题的思路来进行回答。这样你就能直接套用, 从而避免你的回答只停留在表面现象上。1. 设计锁升级机制这个问题, 它背后的动机是什么。核心答案在于追求一种平衡, 既要考虑性能, 又得要兼顾安全性。因为在JDK 1.6这个版本之前, 那种重量级锁的性能开销是非常巨大的。然而在实际的开发过程当中, 绝大多数场景下, 锁的竞争其实并不激烈, 经常出现的是单线程序列持有资源, 或者是多个线程交替持有资源的情况。鉴于上述情况, 系统里便引入了偏向锁与轻量级锁这两种机制。借助于这些机制, 可以在没有竞争发生, 或者只是处于轻度竞争的这类场景里面, 大幅度地去降低锁所带来的额外开销。并且只有当确实遇到了重度竞争的情况时, 锁才会进一步升级成为重量性锁。通过这样的方式进行优化, 就实现了一种按需进行升级以及自适应优化的效果, 从而在整体上兼顾了运行时的性能表现与安全层面的保障。2. 大家可能都很好奇, 那个偏向锁到底是通过什么样的方式去提升具体的性能表现方面的情况。核心答案: 偏向锁的核心设计思路是比较偏向那个最先去拿到锁的线程, 这种做法不需要执行什么比较并交换操作, 完全用不着去切换那种内核模式的状态层次, 同样也不会出现把某个线程给挂起阻塞起来的情况, 一旦这个线程下次再想去获取这个锁的时候呢, 它只做一个动作就行, 就是去检查一下那个对象头部里面存放着的偏向线程标识符是不是等于自己当前的编号, 如果检查出来的结果说这个编号确实就是自己的话, 那它就直接把这个锁给拿到了, 整个过程带来的额外消耗可以说是几乎没有, 所以在性能表现方面它是极其接近于完全没有锁的那种状态的。3. 那个轻量级锁所带有的一种叫做自旋的机制, 它的主要作用是什么? 还有, 这种自旋的行为为什么会被设定一个上限值?关于自旋机制的作用, 需要指出的是: 在轻量级锁竞争这种场景下, 线程会通过自旋这种方式来进行操作, 也就是说, 线程会用循环尝试CAS来获取锁的手段, 去直接避免线程陷入被阻塞的状态里, 这一做法的本质, 是用CPU的持续时间来交换掉因为线程阻塞所可能带来的一些额外开销部分, 并且, 这种策略非常契合那些锁持有时间比较短的相关场景状况同时, 对于自旋为什么要有上限原因的解释, 应当是如果锁持有的时间过长的话, 那么自旋操作就会呈现出一种持续消耗CPU资源的极端状态, 这样的结果必然会导致CPU的利用率变得异常高, 进而反而会大幅度地降低整体性能的表现效果, 所以必须设置出比如默认值为10次的这样一个自旋上限条件, 当次数超过上限之后, 系统就会自动升级为重量级 locks, 使得原本处于自旋状态的线程进入被阻塞的休眠状态中, 以此来有效地削减CPU资源的过度消耗问题。4. 锁升级为什么不可逆核心答案其实说简单点, 就是为了把JVM的实现给简化掉, 进而降低那些锁管理方面的复杂程度。一旦某个锁升级成了重量级锁, 这就意味着当前的锁竞争激烈得很严重, 后续即便竞争情况稍微缓解了一点, 它也不会再降级回去变成轻量级锁或者偏向锁, 这是因为要完成降级这个动作, 就得去增加额外的判断环节和操作步骤, 比如说要去检查锁到底有没有在竞争, 还要去修改那个对象头里面的内容, 这样一来就会白白地增加JVM本身的开销, 最后的结果肯定是得不偿失的, 所以整个设计才定成了不可逆这么一个样子。5. 锁升级这个情况, 到底它和别的事情之间有什么不一样的地方呢。核心答案如下: 第一点在于核心作用存在差异, 锁升级属于一种优化机制, 它的核心目的在于解决问题, 所解决的问题是并发安全问题, 而并发安全问题涉及到三个方面的内容, 分别是原子性、可见性以及有序性, 所以它旨在保证这三个方面, 相比之下另一者仅能保证可见性和有序性这两点, 却无法保证原子性第二点在于底层的实现方式完全不同, 锁升级的实现是基于对象头中的锁状态进行的修改操作, 并且这一过程依赖于比较并交换技术、自旋技巧以及操作系统层面的互斥锁等手段, 而另一者的实现则是完全基于内存屏障来进行的第三点体现在性能表现的区别上, 当进行锁升级之后, 不同级别之间的锁在性能方面会出现较大的差距, 变化明显, 另一者始终维持轻量级无锁的这种机制形态, 因此其性能能够保持相对稳定, 不过相对应的功能覆盖范围是有限的。锁升级的实际体现结合代码演示锁升级的场景, 来帮助理解不同锁级别的触发条件。在面试场景中, 你可以把这个场景结合起来, 说明锁升级的具体流程。这样能够体现出你的实战理解能力。在场景1里面, 单线程持有锁偏向锁。public class BiasLockDemo {// 锁对象private static final Object lock new Object();public static void main(String[] args) {// 单线程反复获取、释放锁触发偏向锁for (int i 0; i 1000; i) {synchronized (lock) {// 同步代码块无其他线程竞争System.out.println(单线程持有锁触发偏向锁);}}}}关键的说明内容是, 由于单线程反复持有锁且没有任何竞争情形, 因此JVM会自动触发偏向锁。在这一状态下, 对象头中会存储当前线程的ID信息。同时, 锁标记位被设置为01。这种状态对应的是偏向锁类型。在这种情况下, 性能表现是最为优异的。在第二种场景里面, 多个线程会去轮流拿着锁这个东西, 并且这个锁属于轻级别的锁。public class LightweightLockDemo {private static final Object lock new Object();public static void main(String[] args) {// 两个线程交替获取锁轻度竞争触发轻量级锁new Thread(() - {for (int i 0; i 100; i) {synchronized (lock) {System.out.println(线程1持有锁);}try {Thread.sleep(10); // 线程1释放锁让线程2获取} catch (InterruptedException e) {e.printStackTrace();}}}).start();new Thread(() - {for (int i 0; i 100; i) {synchronized (lock) {System.out.println(线程2持有锁);}try {Thread.sleep(10); // 线程2释放锁让线程1获取} catch (InterruptedException e) {e.printStackTrace();}}}).start();}}这里有关键说明: 这两个线程在交替进行获取锁的操作, 不存在同时竞争的情况。偏向锁被撤销之后, 升级为轻量级锁。线程是通过使用CAS加上自旋的方式来获取锁的, 没有发生阻塞的现象, 性能表现处于中等水平。强场景三: 强多个线程在一块儿同时去争那个锁, 也就是重量级锁的情况。强/强 /。public class HeavyweightLockDemo {private static final Object lock new Object();public static void main(String[] args) {// 10个线程同时竞争锁重度竞争触发重量级锁for (int i 0; i 10; i) {new Thread(() - {synchronized (lock) {try {// 锁持有时间较长加剧竞争Thread.sleep(100);System.out.println(Thread.currentThread().getName() 持有锁);} catch (InterruptedException e) {e.printStackTrace();}}}).start();}}}这里有一个非常重要的说明需要让大家清楚明白, 那就是当有整整十个线程在一起竞争同一个锁的时候, 如果这个锁被持有的时间变得很长了, 那么原本使用的轻量级锁在自旋次数达到了允许的上限之后, 就会不得不膨胀成为一个重量级锁, 这时候如果有线程没有成功拿到锁, 它就一定会被阻塞住, 并且会被放进了等待队列里面去排队, 这样一来所产生的性能开销也就变得大到不能再大了。总结这篇文章主要是讨论了锁升级这个流程, 具体来说就是先从偏向锁变成轻量级锁, 接着再变成重量级锁, 其中的核心重点可以被总结成三个方面的内容, 这样的归纳是非常适合用于面试时候回答问题的逻辑的, 同时也方便了人们进行记忆和表达。1. 关于锁的升级, 它有一个特定的背景情况。在JDK 1.6这个版本里, 系统是为了解决重量级锁所带来的性能问题。为了实现按需升级这种自适应的机制, 开发人员引入了偏向锁和轻量级锁这两个新的概念。通过这样做, 可以在性能和安全之间找到一个平衡点。2. 其核心运行流程表现为从无锁状态开始, 进而转变为偏向锁状态, 这种偏向锁状态适用于单线程且不存在竞争的场合, 随后可能演变为轻量级锁状态, 这一状态对应的是多线程交替执行并伴有自旋操作的情形, 如果矛盾进一步升级则进入重量级锁状态, 该状态针对的是多线程同时竞争资源导致阻塞的情况, 在整个过程中状态的变迁是绝对不可逆的, 所谓的核心重点在于对对象头部中的锁状态标记数据进行修改。3. 在面试中, 各级别锁的底层实现、锁升级的触发条件、锁升级不可逆的原因、自旋机制的作用等知识点是经常被考察到的内容。如果能够掌握这些核心点, 就可以清晰地拆解出相应的优化逻辑, 这样能够充分体现自身的技术深度。在做面试的时候, 大家常常会把这个考点放到一起问。提问的内容通常包括并发安全问题、锁机制的具体细节, 还有Java虚拟机优化方面的内容。比如说, 有人会问对象的锁升级流程到底是怎么回事儿。也有的人会问偏向锁跟轻量级锁之间有什么区别。还有人可能会问为什么轻量级锁会变成重量级锁这些问题。只要你理解了这篇文章里讲的核心要点, 你就能够很轻松地回答面试官提出的各种追问。这样做的结果会让你的面试通过率有所提高。