synchronized是Java多线程编程中常用的同步机制,其底层实现和锁升级过程备受关注。本文通过代码示例深入分析了synchronized的底层原理和锁的升级路径:无锁、偏向锁、轻量级锁和重量级锁。
分析代码示例和运行结果以下Java代码演示了synchronized锁的升级过程:
public static void main(String[] args) throws InterruptedException { Thread.sleep(5000); Object obj = new Object(); System.out.println("初始状态 =====================" + "\n" + ClassLayout.parseInstance(obj).toPrintable()); new Thread(() -> { synchronized (obj) { System.out.println(Thread.currentThread().getName() + "获取锁执行。。。。\n" + ClassLayout.parseInstance(obj).toPrintable()); } }, "Thread-A").start(); Thread.sleep(1000); new Thread(() -> { synchronized (obj) { System.out.println(Thread.currentThread().getName() + "获取锁执行。。。\n" + ClassLayout.parseInstance(obj).toPrintable()); } }, "Thread-B").start(); Thread.sleep(5000); System.out.println(Thread.currentThread().getName() + ClassLayout.parseInstance(obj).toPrintable()); }
运行结果(可能因JVM版本而异): 显示对象头Mark的结果 Word在不同线程访问中的状态变化显示了锁的升级过程。 在现代JVM中,由于偏向锁通常默认关闭,您可能会观察到从无锁状态直接升级到轻量级锁的状态变化。
synchronized底层机制基于Hotspot虚拟机的synchronized的监视器锁(Monitor)实现,依赖对象头中的Mark Word和操作系统互斥锁(Mutex Lock)。Mark Word存储对象的运行数据,包括锁定状态。
1. 无锁状态: 对象的初始状态,Mark Word存储哈希码等信息。
2. 偏向锁状态: 当只有一个线程访问同步块时,JVM会偏向于锁优化,Mark Word记录线程ID。 这减少了不必要的CAS操作,提高了性能。 (现代JVM通常默认关闭)
3. 轻量级锁状态: 当第二线程试图获得锁时,如果有偏向锁(或偏向锁失效),则升级为轻量级锁。 线程在栈帧中创建锁记录,并尝试使用CAS操作Mark 用指向锁记录的指针代替Word。成功获得锁,失败升级为重量级锁。
4. 重量级锁状态: 轻量级锁竞争失败(CAS操作失败),锁升级为重量级锁。 线程堵塞依赖于操作系统Mutex Lock实现同步,性能成本高。
结果分析总结在代码示例中,锁状态会经历不同的阶段,这反映了synchronized的锁升级机制。 需要注意的是,由于JVM的优化策略,偏向锁可能会被禁用,从无锁状态直接升级到轻量级锁。 了解synchronized的锁升级机制,有助于开发者更有效地利用这一同步工具,并根据实际情况选择合适的锁策略。 现代JVM的优化策略使Synchronized在许多情况下具有较高的性能。
以上是synchronized的底层原理和锁升级机制是什么?详情请关注图灵教育的其他相关文章!
