用 JOL 验证 synchronized 的锁升级过程(偏向锁 → 轻量级锁 → 重量级锁)

文章目录

  • [一、验证偏向锁(Biased Lock)](#一、验证偏向锁(Biased Lock))
  • [二、验证轻量级锁(Lightweight Lock)](#二、验证轻量级锁(Lightweight Lock))
  • [三、验证重量级锁(Heavyweight Lock)](#三、验证重量级锁(Heavyweight Lock))
  • [四、总结:如何用 JOL 清晰地观察锁升级过程?](#四、总结:如何用 JOL 清晰地观察锁升级过程?)

如何用 Java Object Layout (JOL) 工具验证 Java 中 synchronized 的三种锁升级过程。

Maven 依赖:

xml 复制代码
<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.17</version>
</dependency>

一、验证偏向锁(Biased Lock)

⚠️ JVM 默认延迟偏向锁 4 秒

因此要么 -XX:BiasedLockingStartupDelay=0,要么 Thread.sleep 等待 4 秒。

java 复制代码
public class JOLDemoBias {
    static class A {}
    
    public static void main(String[] args) throws Exception {
        A a = new A();
        System.out.println("无锁:");
        System.out.println(ClassLayout.parseInstance(a).toPrintable());

        Thread.sleep(5000); // 等待偏向锁生效

        synchronized (a) {
            System.out.println("偏向锁:");
            System.out.println(ClassLayout.parseInstance(a).toPrintable());
        }
    }
}

观测点:

偏向锁时 mark word 的最后3 位是 101

并且会包含 ThreadId(偏向线程的 ID)。


二、验证轻量级锁(Lightweight Lock)

轻量级锁发生在 同一线程重复进入 synchronized,或多个线程竞争但没有阻塞时。

java 复制代码
public class JOLDemoLight {
    static class A {}
    public static A a = new A();

    public static void main(String[] args) throws Exception {
        Thread.sleep(5000); // 偏向锁激活

        synchronized (a) {
            System.out.println("偏向锁:");
            System.out.println(ClassLayout.parseInstance(a).toPrintable());
        }

        Thread t1 = new Thread(() -> {
            synchronized (a) {
                System.out.println("轻量级锁:");
                System.out.println(ClassLayout.parseInstance(a).toPrintable());
            }
        });

        t1.start();
        t1.join();
    }
}

观测点:

轻量级锁时 mark word 的最后3 位是 00

并且 mark word 指向线程栈中的 Lock Record(栈中一个 pointer)


三、验证重量级锁(Heavyweight Lock)

多个线程竞争导致阻塞后,会升级为重量级锁。

java 复制代码
public class JOLHeavyDemo {
    static class A {}
    static A a = new A();

    public static void main(String[] args) throws Exception {
        Thread.sleep(5000); // 偏向锁激活
        System.out.println("初始:");
        System.out.println(ClassLayout.parseInstance(a).toPrintable());

        Thread t1 = new Thread(() -> {
            synchronized (a) {
                try { Thread.sleep(2000); } catch (Exception ignored) {}
            }
        });

        Thread t2 = new Thread(() -> {
            synchronized (a) {
                System.out.println("重量级锁:");
                System.out.println(ClassLayout.parseInstance(a).toPrintable());
            }
        });

        t1.start();
        Thread.sleep(100); // 保证 t1 先进入同步块
        t2.start();

        t1.join();
        t2.join();
    }
}

观测点:

重量级锁时:

  • mark word 的最后 3 位是 10
  • 其余部分存放一个指向 Monitor 对象(OS 层的 mutex) 的指针

表现为 JOL 输出里面出现:

复制代码
monitor (owner ... )

四、总结:如何用 JOL 清晰地观察锁升级过程?

锁状态 Mark Word 低三位 特征
无锁(Normal) 001 hash 未计算时更多空间用于 MarkWord
偏向锁 101 有 ThreadId
轻量级锁 00 指向线程栈中 Lock Record
重量级锁 10 指向 Monitor 对象

相关推荐
陕西企来客17 分钟前
2026 西安 GEO 优化技术解析:前沿技术与行业规范深度企来客科技行业白皮书声明
开发语言·搜索引擎·php
AI科技星20 分钟前
基于光速螺旋第一性原理:$G,\varepsilon_0,\alpha$引电统一完整推导+严谨证明+高精度数值全维度分析
c语言·开发语言·网络·量子计算·agi
淘矿人1 小时前
DeepSeek V4对决Claude 4.8:AI模型终极横评
java·开发语言·人工智能·python·sql·php·pygame
skywalk81631 小时前
你希望的「多路捕获」语法是哪种形式?具体而言,「捕获 类型为 e」指的是什么?
开发语言·编程
两年半的个人练习生^_^2 小时前
JMM 进阶:彻底理解 volatile 实现原理
java·开发语言
晚风吹红霞2 小时前
C++模板进阶:非类型参数、特化、分离编译与优缺点解析
开发语言·c++
小小龙学IT2 小时前
Go语言后端开发入门指南
开发语言·后端·golang
不会C语言的男孩2 小时前
C++ Primer 第8章:IO 库
开发语言·c++
兰令水2 小时前
leecodecode【层序遍历】【2026.6.3打卡-java版本】
java·开发语言
Halo_tjn2 小时前
反射与设计模式2
java·开发语言·算法