Java锁升级机制超详细讲解(附实例代码)

 更新时间:2025年06月14日 14:05:16   作者:java金融  
Java中的synchronized锁会经历一个从无锁到偏向锁,再到轻量级锁,最后到重量级锁的升级过程,这种优化称为锁升级或锁膨胀,这篇文章主要介绍了Java锁升级机制超详细讲解的相关资料,需要的朋友可以参考下

引言

最近有个三年左右的兄弟面试java 被问到这样一道经典的八股文面试题: 你讲讲java里面的锁升级? 他感觉回答的不是很好,然后回去找资料学习了一波,然后下面是他输出的文章,希望对找工作的其他朋友也有些帮助。

1. 概述

Java 的锁升级机制是 JVM 在 JDK 1.6 后引入的重要优化策略,目的是在多线程环境下平衡 线程安全 与 性能开销。通过动态调整锁的复杂度,JVM 根据竞争强度逐步升级锁的状态,避免在低竞争场景下使用高成本的重量级锁。

2. 锁类型及特点

锁类型适用场景性能开销核心机制
无锁(Unlocked)无线程竞争极低直接通过 CAS 操作尝试获取锁。
偏向锁(Biased Locking)单线程重复访问(无竞争)极低对象头记录偏向线程 ID,后续同一线程无需竞争,直接获取锁。
轻量级锁(Lightweight Lock)低竞争(多个线程交替访问)中等通过 CAS 自旋尝试获取锁,避免操作系统级别的阻塞。
重量级锁(Heavyweight Lock)高竞争(长时间阻塞或高并发)依赖操作系统互斥量(Mutex),线程被挂起并排队等待。

3. 锁升级的过程

锁升级路径为:无锁 → 偏向锁 → 轻量级锁 → 重量级锁,且 不可逆(只能升级,不能降级)。

3.1 无锁 → 偏向锁

  • 触发条件:第一个线程访问同步代码块时。
  • 过程

    JVM 通过 CAS 操作将对象头的 Mark Word 标记为偏向锁。

    记录当前线程 ID 和偏向时间戳。

    后续同一线程再次访问时,直接通过比对线程 ID 获取锁(无需 CAS 操作)。

3.2 偏向锁 → 轻量级锁

  • 触发条件:第二个线程尝试获取同一锁(出现竞争)。
  • 过程

    偏向锁失效,JVM 撤销偏向锁(可能触发 STW,Stop-The-World)。

    线程通过自旋(Spin)和 CAS 操作尝试获取锁。

    若自旋成功,则升级为轻量级锁;否则继续自旋或升级为重量级锁。

3.3 轻量级锁 → 重量级锁

  • 触发条件
    • 自旋次数超过阈值(默认 10 次,可通过 -XX:PreBlockSpin 调整)。
    • 多个线程同时竞争锁(如第三个线程加入竞争)。
  • 过程

    JVM 将锁升级为重量级锁,对象头指向监视器(Monitor)。

    线程进入操作系统内核态的阻塞队列,等待调度器唤醒。

    未获取锁的线程通过 ObjectMonitor 等待唤醒。

4. 锁升级的优缺点

4.1 优点

  • 减少无竞争场景的开销:偏向锁和轻量级锁避免了频繁的 CAS 和上下文切换。
  • 动态适配竞争强度:在低竞争时保持高性能,在高竞争时保证线程安全。

4.2 缺点

  • 偏向锁撤销开销:当其他线程竞争时,撤销偏向锁会导致 STW,影响性能。
  • 重量级锁的高开销:在高竞争场景下,频繁的线程阻塞/唤醒会显著降低性能。

5. 锁升级的优化策略

5.1 减少锁持有时间

  • 优化方向:缩短同步代码块的执行时间,降低锁的竞争概率。
  • 示例
    // 不推荐:锁持有时间过长
    synchronized (lock) {
        // 复杂计算或 IO 操作
    }
    
    // 推荐:仅在关键代码块加锁
    int result = doSomeComputation(); // 非同步操作
    synchronized (lock) {
        sharedVariable = result;
    }
    

5.2 使用分段锁(Segment Locking)

  • 优化方向:将一个大锁拆分为多个小锁,减少锁的竞争范围。
  • 示例ConcurrentHashMap 使用分段锁(JDK 8 后改为 CAS + synchronized)。

5.3 禁用偏向锁

  • 适用场景:频繁切换线程的场景(如高并发服务)。
  • JVM 参数
    -XX:-UseBiasedLocking  # 禁用偏向锁
    

5.4 调整自旋次数

  • 适用场景:轻量级锁的自旋可能因 CPU 空闲而浪费资源。
  • JVM 参数
    -XX:PreBlockSpin=5  # 设置自旋次数为 5
    

6. 代码示例

public class LockUpgradeExample {
    private final Object lock = new Object();

    public void performTask() {
        synchronized (lock) {
            // 同步代码块
        }
    }

    public static void main(String[] args) {
        LockUpgradeExample example = new LockUpgradeExample();
        Thread t1 = new Thread(example::performTask);
        Thread t2 = new Thread(example::performTask);

        t1.start(); // 初始为偏向锁(t1)
        t2.start(); // 触发偏向锁撤销,升级为轻量级锁
    }
}

7. 关键 JVM 参数

参数作用
-XX:+UseBiasedLocking开启/关闭偏向锁(默认开启,Java 15+ 默认关闭)。
-XX:BiasedLockingStartupDelay=0立即启用偏向锁(避免延迟)。
-XX:PreBlockSpin设置轻量级锁自旋次数(默认 10)。
-XX:-UseSpinning关闭自旋锁(强制进入重量级锁)。

8. 总结

  • 锁升级是 JVM 自动管理的机制,开发者无需手动干预,但理解其原理有助于优化并发性能。
  • 偏向锁适合单线程场景,轻量级锁适合低竞争场景,重量级锁适合高竞争场景。
  • 锁升级不可逆,一旦升级到重量级锁,后续操作将始终使用重量级锁。

通过合理设计代码(如减少锁粒度、避免过早膨胀到重量级锁),可以最大化 Java 的并发性能。

到此这篇关于Java锁升级机制的文章就介绍到这了,更多相关Java锁升级机制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java中Thread类详解及常用的方法

    Java中Thread类详解及常用的方法

    在java中谈到线程,必然少不了Thread类,下面这篇文章主要给大家介绍了关于Java中Thread类及常用的方法,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-05-05
  • java ssm框架实现分页功能的示例代码(oracle)

    java ssm框架实现分页功能的示例代码(oracle)

    这篇文章主要介绍了java ssm框架实现分页功能的示例代码(oracle),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-03-03
  • 使用idea连接浏览器进行访问过程

    使用idea连接浏览器进行访问过程

    配置IDEA WebBrowsers路径:打开IDEA,进入File→Setting,搜索Web,设置浏览器绝对路径至ProgramFiles或ProgramFiles(x86)(根据程序位数),复制路径解决访问问题
    2025-09-09
  • IDEA个性化设置注释模板详细讲解版

    IDEA个性化设置注释模板详细讲解版

    IDEA自带的注释模板不是太好用,我本人到网上搜集了很多资料系统的整理了一下制作了一份比较完整的模板来分享给大家,下面这篇文章主要给大家介绍了IDEA个性化设置注释模板的相关资料,需要的朋友可以参考下
    2024-01-01
  • Spring Validator接口校验与全局异常处理器

    Spring Validator接口校验与全局异常处理器

    这篇文章主要介绍了Spring Validator接口校验与全局异常处理器,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-11-11
  • Spring MVC的参数绑定和返回值问题

    Spring MVC的参数绑定和返回值问题

    这篇文章主要介绍了Spring MVC的参数绑定和返回值问题,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-02-02
  • 浅析java 归并排序算法

    浅析java 归并排序算法

    这篇文章主要简单介绍了java 归并排序算法的工作原理及代码,需要的朋友可以参考下
    2015-02-02
  • mybatis generator 使用方法教程(生成带注释的实体类)

    mybatis generator 使用方法教程(生成带注释的实体类)

    下面小编就为大家带来一篇mybatis generator 使用方法教程(生成带注释的实体类)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-08-08
  • java进阶之了解SpringBoot的配置原理

    java进阶之了解SpringBoot的配置原理

    今天带大家了解SpringBoot的相关知识,文中对SpringBoot的配置原理作了非常详细的图文示例及介绍,需要的朋友可以参考下
    2021-06-06
  • Java I/O流实例之简历替换

    Java I/O流实例之简历替换

    流是一种抽象概念,它代表了数据的无结构化传递。。用来进行输入输出操作的流就称为IO流。换句话说,IO流就是以流的方式进行输入输出
    2021-09-09

最新评论