偏向锁

简介: 偏向锁是JVM为提升单线程环境下锁性能而引入的优化机制。其核心思想是将锁偏向首个获取它的线程,避免无竞争时的同步开销,从而提高执行效率。适用于锁由同一线程多次获取、无并发竞争的场景。一旦出现多线程竞争,偏向锁会撤销并升级为更高级别的锁。合理使用可显著提升性能,但在高并发环境下需谨慎配置。

偏向锁(Biased Locking)是Java虚拟机(JVM)为提高单线程环境下的锁性能而引入的一种优化机制。它通过偏向某个线程,避免了无竞争情况下的锁获取和释放开销,进一步提升了同步代码的执行效率。

核心原理

  1. 锁对象的偏向状态
    当锁对象第一次被线程获取时,JVM会在对象头的Mark Word中记录该线程的ID,称为偏向线程。此后,该线程再次进入同步块时,无需任何同步操作(如CAS或互斥量),直接获得锁。

  2. Mark Word的结构变化

    • 无锁状态:Mark Word存储哈希码、分代年龄等信息。
    • 偏向锁状态:Mark Word存储偏向线程ID、时间戳等信息。

偏向锁的获取与撤销流程

  1. 获取锁

    • 首次获取锁时,通过CAS操作将线程ID写入对象头Mark Word。
    • 成功后,该线程成为偏向线程,后续访问无需任何同步操作。
  2. 撤销锁
    当有其他线程尝试竞争偏向锁时,偏向锁会被撤销,恢复到无锁状态或升级为轻量级锁。撤销操作需要暂停拥有偏向锁的线程,修改Mark Word,并恢复线程执行。

偏向锁的优缺点

  • 优点

    • 无竞争时零开销:单线程重复获取锁的场景下,完全消除了CAS和互斥量的开销。
    • 实现简单:仅需修改对象头Mark Word,无需额外的数据结构。
  • 缺点

    • 偏向撤销成本高:涉及线程暂停和恢复,在竞争频繁的场景下可能成为性能瓶颈。
    • 不适用于多线程竞争:一旦发生竞争,偏向锁的撤销和升级操作会带来额外开销。

偏向锁的适用场景

  • 单线程主导的同步块:如Servlet容器处理HTTP请求的线程池。
  • 锁竞争极少发生:如初始化阶段的同步操作。
  • 锁被同一线程长期持有:如单例模式的双重检查锁定。

Java中的偏向锁示例

以下代码展示了偏向锁在单线程环境下的性能优势:

public class BiasedLockExample {
   
    private static final Object lock = new Object();
    private static int counter = 0;

    public static void main(String[] args) {
   
        // 预热JVM,触发偏向锁
        for (int i = 0; i < 1000; i++) {
   
            synchronized (lock) {
   
                counter++;
            }
        }

        // 单线程重复获取锁(偏向锁生效)
        long startTime = System.nanoTime();
        for (int i = 0; i < 1000000; i++) {
   
            synchronized (lock) {
   
                counter++;
            }
        }
        long endTime = System.nanoTime();

        System.out.println("单线程执行时间: " + (endTime - startTime) / 1000000 + " ms");
        System.out.println("Counter: " + counter);
    }
}

执行流程

  1. 预热阶段:JVM会默认延迟启用偏向锁(约4秒),首次同步块会触发偏向锁的初始化。
  2. 正式测试:单线程重复获取锁,由于没有竞争,偏向锁无需任何同步操作,执行速度极快。

JVM对偏向锁的优化

  1. 偏向锁延迟初始化
    JVM启动初期(默认4秒)禁用偏向锁,避免系统初始化阶段的竞争导致频繁撤销。

  2. 批量重偏向(Bulk Rebias)
    当一个对象被多个线程交替访问,但不存在竞争时,JVM会批量重置偏向锁,指向新的线程。

  3. 批量撤销(Bulk Revoke)
    当某个类的对象频繁发生偏向锁撤销时,JVM会将该类所有对象的偏向锁永久撤销,直接升级为轻量级锁。

偏向锁的配置参数

通过JVM参数可以调整偏向锁的行为:

  • -XX:+UseBiasedLocking:启用偏向锁(默认开启,JDK 15+默认关闭)。
  • -XX:BiasedLockingStartupDelay=0:取消偏向锁启动延迟。
  • -XX:-UseBiasedLocking:禁用偏向锁,所有锁直接升级为轻量级锁。

偏向锁与其他锁的对比

锁类型 适用场景 锁获取开销 锁释放开销 竞争处理方式
偏向锁 单线程重复获取锁 首次CAS,后续0 0 撤销并升级
轻量级锁 多线程交替获取锁 CAS CAS 升级为重量级锁
重量级锁 多线程同时竞争锁 内核互斥量 内核互斥量 线程阻塞

总结

偏向锁是JVM针对单线程场景的极致优化,通过消除无竞争情况下的同步开销,显著提升了性能。但在多线程竞争频繁的场景下,偏向锁的撤销和升级操作可能成为性能瓶颈,此时应考虑禁用偏向锁或使用其他并发工具。理解偏向锁的工作原理有助于优化高并发系统的性能。

目录
相关文章
|
2月前
|
缓存 Java
对比 synchronized 和 volatile
`synchronized` 和 `volatile` 是 Java 并发编程中的两个关键机制,各有侧重。`synchronized` 用于实现线程的互斥访问,保证原子性、可见性和有序性,适用于需要锁的场景;而 `volatile` 更轻量,仅确保变量的可见性和有序性,适用于状态标志等无需复合操作的场景。两者可互补使用,如双重检查单例中结合二者优势。合理选择有助于提升并发性能与代码安全性。
120 0
|
2月前
|
Java Spring
Spring Boot配置的优先级?
在Spring Boot项目中,配置可通过配置文件和外部配置实现。支持的配置文件包括application.properties、application.yml和application.yaml,优先级依次降低。外部配置常用方式有Java系统属性(如-Dserver.port=9001)和命令行参数(如--server.port=10010),其中命令行参数优先级高于系统属性。整体优先级顺序为:命令行参数 &gt; Java系统属性 &gt; application.properties &gt; application.yml &gt; application.yaml。
528 0
|
运维 监控 数据可视化
日志服务 HarmonyOS NEXT 日志采集最佳实践
鸿蒙操作系统(HarmonyOS)上的日志服务(SLS)SDK 提供了针对 IoT、移动端到服务端的全场景日志采集、处理和分析能力,旨在满足万物互联时代下应用的多元化设备接入、高效协同和安全可靠运行的需求。
117800 110
|
2月前
|
存储 Java 对象存储
轻量级锁
轻量级锁是JVM为提升多线程性能而引入的锁机制,通过CAS操作减少线程阻塞,适用于同步块执行时间短且线程竞争不激烈的场景。其核心在于使用栈帧中的锁记录与CAS操作实现高效加锁,避免用户态与内核态切换带来的性能损耗。当无竞争时,仅需一次CAS即可完成锁获取;若竞争激烈,则可能升级为重量级锁。相比偏向锁和重量级锁,轻量级锁在低竞争环境下具有更高的效率。
77 0
|
弹性计算 安全 Linux
Linux服务器总是被暴力破解,用fail2ban来加强防护(用法详解)
Linux服务器总是被暴力破解,用fail2ban来加强防护(用法详解)
Linux服务器总是被暴力破解,用fail2ban来加强防护(用法详解)
|
2月前
|
缓存 Java 关系型数据库
共享锁
共享锁允许多个线程同时读取共享资源,写操作时阻塞其他线程,通过“读共享、写独占”策略提升并发性能,适用于读多写少场景,如缓存、数据库查询等。
77 0
|
2月前
|
监控 Java 关系型数据库
排他锁
排他锁(写锁)是一种互斥机制,确保同一时间仅一个线程访问共享资源,保障数据一致性与完整性。适用于写操作场景,如更新、删除等,常见于数据库和多线程编程。其优点为强一致性和实现简单,但并发度低且存在死锁风险。可通过synchronized、ReentrantLock等方式实现。
66 0
|
2月前
|
搜索推荐 大数据 索引
插入排序的实现思路
插入排序是一种简单直观的排序算法,通过将每个元素插入已排序序列的合适位置实现排序。具有简单高效、稳定、空间复杂度低等优点,适用于小规模或接近有序的数据排序。
61 0
|
2月前
|
存储 算法 安全
重量级锁
重量级锁是Java中基于操作系统互斥量实现的传统线程同步机制,适用于高竞争场景。其通过对象头指向Monitor,管理线程的阻塞与唤醒,提供强安全性,但性能开销大,涉及用户态与内核态切换。相较轻量级锁,适用于不同竞争程度的同步需求。
52 0
|
6月前
|
缓存 监控 NoSQL
场景题:线上接口响应慢,应该如何排查问题?
面试中常见的接口响应慢排查题旨在考察研发人员的系统性解决问题的能力。回答时需结合业务场景(如大促、高峰期),并运用工具(Arthas、SkyWalking等)进行监控告警、链路追踪和日志分析,明确问题范围及原因。具体步骤包括:1. 定位问题(确认单个接口或整体系统、查看APM指标、分析链路和日志);2. 排查网络、中间件及外部依赖(检测延迟、检查Redis、RocketMQ、MySQL等);3. 服务端性能分析(CPU、内存、磁盘IO、JVM调优)。最后提出优化方案,如代码逻辑、数据库、缓存策略及资源扩容等。总结时可结合实际案例,展示完整的排查与优化流程。
921 4

热门文章

最新文章