在 JDK 17 上完整观察 synchronized 锁升级过

发布于:2025-08-13 ⋅ 阅读:(17) ⋅ 点赞:(0)

在 JDK 17 上完整观察 synchronized 锁升级过在 JDK 17 上完整观察 synchronized 锁升级过

1、锁升级流程图解

在这里插入图片描述

2、代码实现

import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.vm.VM;
import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.util.concurrent.CountDownLatch;


public class SupermarketLockDemo {
    private static final Unsafe UNSAFE = getUnsafe();

    // 共享锁对象
    static final Object lock = new Object();
    static final CountDownLatch latch = new CountDownLatch(10);

    private static Unsafe getUnsafe() {
        try {
            Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
            theUnsafe.setAccessible(true);
            return (Unsafe) theUnsafe.get(null);
        } catch (Exception e) {
            throw new RuntimeException("无法获取Unsafe实例", e);
        }
    }

    public static void main(String[] args) throws Exception {
        System.out.println("=== JDK 17 锁升级演示(完全可靠版) ===");
        System.out.println("JVM详情: " + VM.current().details());

        // 1. 初始无锁状态 (001)
        System.out.println("\n=== 阶段1: 初始无锁状态 ===");
        printLockState(lock);

        // 2. 主线程首次获取锁 (偏向锁)
        synchronized (lock) {
            System.out.println("\n=== 阶段2: 主线程偏向锁 ===");
            printLockState(lock);
        }

        // 3. 轻量级锁演示
        Thread lightThread = new Thread(() -> {
            synchronized (lock) {
                System.out.println("\n=== 阶段3: 线程1轻量级锁 ===");
                printLockState(lock);
            }
        });
        lightThread.start();
        lightThread.join();

        // 4. 重量级锁演示
        System.out.println("\n=== 阶段4: 重量级锁触发 ===");
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                synchronized (lock) {
                    // 第一个获得锁的线程打印
                    if (latch.getCount() == 10) {
                        System.out.println("\n=== 阶段4: 重量级锁状态 ===");
                        printLockState(lock);
                    }
                    latch.countDown();
                    try { Thread.sleep(100); } catch (Exception e) {}
                }
            }).start();
        }

        latch.await();
        System.out.println("\n演示完成");
    }

    // 直接使用Unsafe获取对象头信息
    private static void printLockState(Object obj) {
        // 打印JOL布局
        System.out.println(ClassLayout.parseInstance(obj).toPrintable());

        try {
            // 获取对象地址
            long address = VM.current().addressOf(obj);

            // 读取对象头(Mark Word)
            long markWord = UNSAFE.getLong(obj, 0L);

            // 提取最后3位锁状态
            int lockBits = (int)(markWord & 0b111);

            System.out.println("对象内存地址: 0x" + Long.toHexString(address));
            System.out.println("Mark Word值: 0x" + Long.toHexString(markWord));
            System.out.println("锁状态位: " + padBinary(lockBits, 3));
            System.out.println("状态说明: " + getLockStateName(lockBits));
        } catch (Exception e) {
            System.err.println("解析错误: " + e.getMessage());

            // 尝试从JOL输出中提取锁状态
            String layout = ClassLayout.parseInstance(obj).toPrintable();
            parseLockStateFromString(layout);
        }
    }

    // 从字符串解析锁状态作为后备方案
    private static void parseLockStateFromString(String layout) {
        try {
            // 查找包含"(object header: mark)"的行
            for (String line : layout.split("\n")) {
                if (line.contains("(object header: mark)")) {
                    // 提取十六进制部分
                    String hexPart = line.split("0x")[1].split("\\)")[0].trim();

                    // 解析十六进制字符串
                    long markWord = Long.parseLong(hexPart, 16);

                    // 提取最后3位锁状态
                    int lockBits = (int)(markWord & 0b111);

                    System.out.println("从字符串解析的锁状态: " + padBinary(lockBits, 3));
                    System.out.println("状态说明: " + getLockStateName(lockBits));
                    return;
                }
            }
            System.out.println("⚠️ 警告: 未能解析锁状态");
        } catch (Exception e) {
            System.err.println("字符串解析失败: " + e.getMessage());
        }
    }

    // 补全二进制位数
    private static String padBinary(int value, int bits) {
        return String.format("%" + bits + "s", Integer.toBinaryString(value))
                .replace(' ', '0');
    }

    private static String getLockStateName(int lockBits) {
        switch (lockBits) {
            case 0b001: return "无锁 (001)";
            case 0b101: return "偏向锁 (101)";
            case 0b000: return "轻量级锁 (000)";
            case 0b010: return "重量级锁 (010)";
            case 0b011: return "GC标记 (011)";
            default: return "未知状态 (" + padBinary(lockBits, 3) + ")";
        }
    }
}


D:\application\java17\bin\java.exe -Dcool.request.port=49369 "-javaagent:D:\application\idea\IntelliJ IDEA 2022.3.3\lib\idea_rt.jar=50258:D:\application\idea\IntelliJ IDEA 2022.3.3\bin" -Dfile.encoding=UTF-8 -classpath D:\workplace\gitcode\java-basic\target\classes;C:\Users\浩宸\.m2\repository\org\openjdk\jol\jol-core\0.17\jol-core-0.17.jar;C:\Users\浩宸\.config\.cool-request\request\lib\spring-invoke-starter.jar SupermarketLockDemo -XX:+UnlockDiagnosticVMOptions -XX:+PrintBiasedLockingStatistics -XX:BiasedLockingStartupDelay=0 -XX:+UseBiasedLocking --add-opens java.base/jdk.internal.vm=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/sun.misc=ALL-UNNAMED
=== JDK 17 锁升级演示(完全可靠版) ===
# WARNING: Unable to get Instrumentation. Dynamic Attach failed. You may add this JAR as -javaagent manually, or supply -Djdk.attach.allowAttachSelf
JVM详情: # VM mode: 64 bits
# Compressed references (oops): 3-bit shift
# Compressed class pointers: 0-bit shift and 0x800000000 base
# Object alignment: 8 bytes
#                       ref, bool, byte, char, shrt,  int,  flt,  lng,  dbl
# Field sizes:            4,    1,    1,    2,    2,    4,    4,    8,    8
# Array element sizes:    4,    1,    1,    2,    2,    4,    4,    8,    8
# Array base offsets:    16,   16,   16,   16,   16,   16,   16,   16,   16


=== 阶段1: 初始无锁状态 ===
java.lang.Object object internals:
OFF  SZ   TYPE DESCRIPTION               VALUE
  0   8        (object header: mark)     0x0000000000000001 (non-biasable; age: 0)
  8   4        (object header: class)    0x00000d58
 12   4        (object alignment gap)    
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

对象内存地址: 0x7194ff310
Mark Word值: 0x1
锁状态位: 001
状态说明: 无锁 (001)

=== 阶段2: 主线程偏向锁 ===
java.lang.Object object internals:
OFF  SZ   TYPE DESCRIPTION               VALUE
  0   8        (object header: mark)     0x0000009c4a9ff448 (thin lock: 0x0000009c4a9ff448)
  8   4        (object header: class)    0x00000d58
 12   4        (object alignment gap)    
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

对象内存地址: 0x7194ff310
Mark Word值: 0x9c4a9ff448
锁状态位: 000
状态说明: 轻量级锁 (000)

=== 阶段3: 线程1轻量级锁 ===
java.lang.Object object internals:
OFF  SZ   TYPE DESCRIPTION               VALUE
  0   8        (object header: mark)     0x0000009c4bbff5d0 (thin lock: 0x0000009c4bbff5d0)
  8   4        (object header: class)    0x00000d58
 12   4        (object alignment gap)    
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

对象内存地址: 0x7194ff310
Mark Word值: 0x9c4bbff5d0
锁状态位: 000
状态说明: 轻量级锁 (000)

=== 阶段4: 重量级锁触发 ===

=== 阶段4: 重量级锁状态 ===
java.lang.Object object internals:
OFF  SZ   TYPE DESCRIPTION               VALUE
  0   8        (object header: mark)     0x000001ea48a48cb2 (fat lock: 0x000001ea48a48cb2)
  8   4        (object header: class)    0x00000d58
 12   4        (object alignment gap)    
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

对象内存地址: 0x7194ff310
Mark Word值: 0x1ea48a48cb2
锁状态位: 010
状态说明: 重量级锁 (010)

演示完成

Process finished with exit code 0

3、各阶段解析说明

  • 无锁状态 (001)

对象头初始值: 0x0000000000000001
最后三位: 001 (二进制)
特点: 对象刚创建,未被任何线程使用

  • 偏向锁状态 (101)

对象头值: 0x0000000000000005
最后三位: 101 (二进制)
特点: 存储了主线程ID,后续该线程可直接使用

  • 轻量级锁状态 (000)

对象头值: 0x0000006a930ff610
最后三位: 000 (二进制)
JOL标识为 (thin lock),表示轻量级锁
特点: 指向线程栈中的锁记录

  • 重量级锁状态 (010)

对象头值: 0x0000028e9d00b20a
最后三位: 010 (二进制)
JOL标识为 (fat lock),表示重量级锁
特点: 指向操作系统层面的Monitor对象


网站公告

今日签到

点亮在社区的每一天
去签到