在 JDK 17 上完整观察 synchronized 锁升级过
在 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 VALUE0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)8 4 (object header: class) 0x00000d5812 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 VALUE0 8 (object header: mark) 0x0000009c4a9ff448 (thin lock: 0x0000009c4a9ff448)8 4 (object header: class) 0x00000d5812 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 VALUE0 8 (object header: mark) 0x0000009c4bbff5d0 (thin lock: 0x0000009c4bbff5d0)8 4 (object header: class) 0x00000d5812 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 VALUE0 8 (object header: mark) 0x000001ea48a48cb2 (fat lock: 0x000001ea48a48cb2)8 4 (object header: class) 0x00000d5812 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对象