继续承接上一篇博客一、从Java对象头看synchronized锁的状态 先通过几个案例,从结果直观的展示锁是如何膨胀的 最后将锁的膨胀过程通过一张流程图展示出来 案例1(无锁,不可偏向状态) import org.openjdk.jol.info.ClassLayout; public class Demo1 { public static void main(String[] args) throws InterruptedException { A a = new A(); /// 理论上说这里应该是无锁状态 System.ou 在Java编程语言中,`synchronized`关键字用于实现线程同步,确保多线程环境下的数据一致性。本文将深入分析`synchronized`锁的膨胀过程,这个过程涉及到锁从无锁状态到轻量级锁,再到重量级锁的升级。 我们需要理解Java对象头中的Mark Word,它是一个重要的数据结构,用于存储对象的锁状态和其他信息。在无锁状态下,Mark Word的最后3位是001,表明对象当前没有被锁定,并且不可偏向任何线程。 在案例2中,我们看到即使计算对象的哈希码(`hashCode`),也不会改变锁的状态。这是因为哈希码是延迟加载的,它会占用Mark Word的高31位,但并不会立即触发锁的升级。 当一个线程首次获取对象锁时,如果该对象尚未被其他线程持有,JVM会尝试启用偏向锁。在案例3中,通过添加`Thread.sleep(5000)`,我们模拟了程序启动一段时间后的情况,此时JVM已经激活了偏向锁机制。因此,创建的对象`a`处于无锁且可偏向的状态,Mark Word的最后3位是101,表明这是一个可偏向的无锁对象。 偏向锁的设计是为了优化单线程访问的性能。如果一个线程连续多次获得同一对象锁,那么对象会偏向于这个线程,不再进行同步操作。然而,如果多个线程尝试获取同一偏向锁,那么锁会升级为轻量级锁。轻量级锁主要通过CAS(Compare and Swap)操作来实现,避免了内核态到用户态的切换,提高了性能。 如果轻量级锁也无法满足需求,比如锁的竞争变得激烈,轻量级锁会进一步升级为重量级锁,即 monitors 或 monitor locks,这会导致线程上下文切换到内核态,使用操作系统级别的互斥量来保证同步。此时,Mark Word会存储指向Monitor Object的指针,表明当前对象被重量级锁保护。 了解锁膨胀的过程有助于我们更好地理解和优化多线程代码。例如,可以通过JVM参数调整来控制偏向锁的行为,如`-XX:BiasedLockingStartupDelay=0`可以立即启动偏向锁,`-XX:-UseBiasedLocking`则完全禁用偏向锁。此外,通过`-XX:+PrintFlagsFinal`可以查看各种JVM标志的默认值,以便更好地理解和调试。 总结来说,`synchronized`锁的膨胀过程是从无锁到可偏向的无锁,再到轻量级锁,最后到重量级锁,这个过程中涉及到了Java对象头Mark Word的变更以及JVM的优化策略。理解这个过程有助于我们在设计多线程代码时选择合适的同步策略,提高并发性能。
剩余6页未读,继续阅读
- 粉丝: 4
- 资源: 894
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
评论0