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

Java高频面试之并发编程-19

hello啊,各位观众姥爷们!!!本baby今天又来报道了!哈哈哈哈哈嗝🐶

面试官:synchronized锁升级是什么?

在 Java 中,synchronized 锁升级是 JVM 为了优化同步性能而引入的机制(JDK 1.6+)。其核心思想是:根据线程竞争锁的激烈程度,动态调整锁的级别,从低开销的锁逐步升级到高开销的锁,从而减少不必要的性能损耗。


锁升级的四个阶段

锁的升级过程遵循以下顺序(不可逆):
无锁 → 偏向锁 → 轻量级锁 → 重量级锁


1. 无锁(No Lock)
  • 场景:对象未被任何线程锁定。
  • 特点
    • 初始状态,无同步需求。
    • 适合线程不访问共享资源的场景(如只读操作)。

2. 偏向锁(Biased Lock)
  • 场景:锁始终被同一个线程访问(无竞争)。
  • 原理
    • 在对象头中记录偏向的线程 ID(通过 CAS 操作)。
    • 后续该线程进入同步代码时,无需任何同步操作(直接访问)。
  • 优点:消除无竞争时的锁开销。
  • 升级条件
    • 当其他线程尝试竞争偏向锁时,偏向锁撤销(Revoke),升级为轻量级锁。

3. 轻量级锁(Lightweight Lock)
  • 场景:锁被多个线程交替访问(低竞争)。
  • 原理
    • 线程通过 CAS 自旋尝试获取锁(不会立即阻塞)。
    • 若自旋成功,对象头中存储指向锁记录的指针(Lock Record)。
    • 若自旋失败(超过阈值),升级为重量级锁。
  • 优点:减少线程阻塞带来的上下文切换开销。
  • 升级条件
    • 自旋失败(竞争加剧),或等待线程超过一定数量(默认自旋 10 次或自适应调整)。

4. 重量级锁(Heavyweight Lock)
  • 场景:多线程高竞争。
  • 原理
    • 锁由 JVM 通过操作系统级 互斥量(Mutex) 实现。
    • 未获取锁的线程直接进入阻塞状态(BLOCKED),等待唤醒。
  • 优点:避免 CPU 空转(自旋浪费资源)。
  • 缺点:线程阻塞和唤醒涉及内核态切换,性能开销大。

锁升级流程示意图

无锁 → (线程首次访问) → 偏向锁 → (出现竞争) → 轻量级锁 → (竞争激烈) → 重量级锁

锁升级的底层实现

  • 对象头(Object Header)
    锁状态信息存储在对象头的 Mark Word 中,包含锁标志位、线程 ID、锁记录指针等。

    • 32 位 JVM 的 Mark Word 结构示例:
      | 锁状态   | 25 bits          | 4 bits         | 1 bit (偏向锁) | 2 bits (锁标志) |
      |----------|------------------|----------------|----------------|----------------|
      | 无锁     | 对象的 hashCode  | 分代年龄       | 0              | 01             |
      | 偏向锁   | 线程ID + Epoch   | 分代年龄       | 1              | 01             |
      | 轻量级锁 | 指向锁记录的指针 |                |                | 00             |
      | 重量级锁 | 指向 Monitor 的指针 |              |                | 10             |
      
  • 锁升级触发
    通过 JVM 内置的优化策略(如竞争检测、自旋次数统计)动态调整。


锁升级的意义

  1. 性能优化

    • 避免无竞争或低竞争时直接使用重量级锁的开销。
    • 偏向锁和轻量级锁通过 CAS 和自旋减少线程阻塞。
  2. 适应性

    • 根据实际竞争强度动态调整,平衡吞吐量和响应时间。
  3. 兼容性

    • 保持 synchronized 的语法简洁性,开发者无需手动优化锁级别。

示例:锁升级过程

public class LockUpgradeExample {private static final Object lock = new Object();public static void main(String[] args) {// 线程1首次访问:偏向锁new Thread(() -> {synchronized (lock) {System.out.println("Thread1 获取锁");}}).start();// 线程2竞争:升级为轻量级锁new Thread(() -> {synchronized (lock) {System.out.println("Thread2 获取锁");}}).start();// 高竞争场景:最终升级为重量级锁for (int i = 0; i < 10; i++) {new Thread(() -> {synchronized (lock) {try { Thread.sleep(100); } catch (InterruptedException e) {}}}).start();}}
}

注意事项

  1. 锁降级

    • JVM 不会主动降级锁(如重量级锁不会回退到轻量级锁)。
    • 降级仅在某些特殊场景下发生(如全局安全点检查)。
  2. 偏向锁延迟

    • JVM 默认在启动后 4 秒才启用偏向锁(通过 -XX:BiasedLockingStartupDelay=0 可关闭延迟)。
  3. 禁用锁升级

    • 通过 JVM 参数控制(如 -XX:-UseBiasedLocking 禁用偏向锁)。

在这里插入图片描述

相关文章:

  • 【Qt】在OrinNX上,使用命令安装qtmultimedia5-dev时报错
  • VMware三种网络配置对比
  • 【华为OD- B卷 - 增强的strstr 100分(python、java、c++、js、c)】
  • 如何解决全局或静态变量被修改的bug
  • 高频Java面试题深度拆解:String/StringBuilder/StringBuffer三剑客对决(万字长文预警)
  • SpringBoot 自动配置
  • FEKO许可证与其他电磁仿真软件的比较
  • 2024年热门AI趋势及回顾
  • leetcode 3355. 零数组变换 I 中等
  • PYTHON训练营DAY31
  • ⼆叉搜索树详解
  • 迅为RK3562开发板旋转Uboot logo和内核logo
  • string在c语言中代表什么(非常详细)
  • VitePress 中以中文字符结尾的字体加粗 Markdown 格式无法解析
  • 嵌入式学习笔记 D24 :系统编程之i/o操作
  • PyTorch 之 torch.distributions.Categorical 详解
  • MATLAB中进行语音信号分析
  • USB学习【13】STM32+USB接收数据过程详解
  • 关于element-ui的table type=“expand“ 嵌套表格展开异常问题解决方案
  • CYT4BB Dual Bank 1 - 存储机制
  • 福州市委副书记、福州新区党工委书记陈云水转任三明市政协党组书记
  • 上海黄浦:新婚夫妻来登记可“摇号”定制无人机表演,每周三对
  • 中方是否支持或参加俄乌谈判?外交部:支持一切有利于和平的努力
  • 改造老旧小区、建立“一张图”,五部委将多举措支持城市更新
  • 中青报聚焦上海社区心理服务:社工介入让居民“心畅”
  • 烤肉店从泔水桶内捞出肉串再烤?西安未央区市监局:停业整顿