当前位置: 首页 > 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 禁用偏向锁)。

在这里插入图片描述

http://www.xdnf.cn/news/554347.html

相关文章:

  • 第50天-使用Python+Qt+DeepSeek开发AI运势测算
  • 基于springboot3 VUE3 火车订票系统前后端分离项目适合新手学习的项目包含 智能客服 换乘算法
  • 当前主流的传输技术(如OTN、IP-RAN、FlexE等)
  • C++STL之string
  • 产业互联网+三融战略:重构企业增长密码
  • 人工智能+:职业技能培训的元命题与能力重构
  • Linux 正则表达式 扩展正则表达式 gawk
  • 101个α因子#8
  • Java DTO 深度解析
  • JUC编程monitor、锁膨胀以及相关关键字
  • 定时从接口下载数据到本地
  • 免费插件集-illustrator插件-Ai插件-路径尖角圆角化
  • 天然产物在食品医药美妆领域的创新应用研究
  • 图像噪声模拟
  • 安装PostgreSQL
  • 解决javafx组件缺失导致运行程序报错的问题
  • Spring Boot中的分布式缓存方案
  • PID项目---硬件设计
  • Javascript 编程基础(2)基础知识 | 2.3、语法规则
  • 操作系统----软考中级软件工程师(自用学习笔记)
  • 循环神经网络
  • 机器人编程基础---C语言中的高级特性
  • upload-labs通关笔记-第13关 文件上传之白名单POST法
  • 旧物回收系统:撬动绿色经济新支点,开启循环未来新篇章
  • 区县与地级市和省会的距离
  • LW-CTrans:一种用于三维医学图像分割的轻量级CNN与Transformer混合网络|文献速递-深度学习医疗AI最新文献
  • JavaScript 性能优化:调优策略与工具使用
  • NumPy 2.x 完全指南【十三】复制和视图
  • 使用ZYNQ芯片和LVGL框架实现用户高刷新UI设计系列教程(第十三讲)
  • 口腔牙科小程序源码介绍