随笔录--synchronized是什么

在 Java 中,synchronized 是实现同步的基本方法之一,既可以修饰方法也可以修饰代码块。其内部实现依赖于 JVM 层面的监视器锁(Monitor Lock),但它的工作原理和锁的状态变化较为复杂,涉及锁的升级与降级。

synchronized 的底层实现

监视器锁(Monitor)

synchronized 关键字的实现依赖于 JVM 内部的一个概念叫做监视器锁(Monitor)。每个对象都有一个监视器锁,当这个对象被用作同步时,执行同步代码的线程必须首先获得这个对象的监视器锁。

对象头(Object Header)

在 JVM 中,对象在内存中的布局包括对象头、实例数据和对齐填充。对象头包含了对象的运行时数据,如哈希码、GC 分代年龄、锁状态标志等。对于锁的实现,特别是锁的状态,是通过对象头中的一部分来表示的。

锁的状态

1)轻量级锁:当一个线程进入同步块时,如果目标对象没有被锁定,JVM 会在当前线程的栈帧中创建用于锁记录的空间,尝试使用 CAS 操作将对象头的 Mark Word 更新为指向锁记录的指针。如果成功,当前线程获得锁,进入轻量级锁状态。

2)重量级锁:如果轻量级锁的竞争失败(例如,另一个线程已持有该锁),锁会膨胀为重量级锁。此时,JVM 会在对象头上设置指向一个监视器(Monitor)的指针,线程将会进入阻塞状态,直到锁可用。

3)偏向锁:JVM 也采用了偏向锁来优化同步性能。当锁被第一次获取时,对象头会被标记为偏向模式,并记录获取它的线程 ID。之后,该线程进入同步块时不需要进行任何同步操作。如果在偏向模式下,另一个线程尝试获取锁,偏向模式会被撤销,锁会升级为轻量级锁或重量级锁。

锁的升级与降级

锁升级

1)从无锁到偏向锁:当一个线程首次访问同步块时,会将对象头设置为偏向锁状态,标记为该线程所有。

2)从偏向锁到轻量级锁:当有另一个线程尝试获取已被偏向的锁时,如果持有偏向锁的线程不活跃,JVM 将取消偏向模式,升级锁为轻量级锁。

3)从轻量级锁到重量级锁:当轻量级锁的竞争发生时,即 CAS 失败,锁会升级为重量级锁,线程进入阻塞状态,等待锁释放。

锁降级

锁降级是指锁状态从重量级锁转变为轻量级锁或偏向锁的过程。在 Java 的 synchronized 实现中,锁降级的概念并不显著,主要是因为一旦锁升级为重量级锁,就很少会降级。锁的降级主要出现在 JVM 对锁状态的优化过程中,例如在锁竞争减少时,JVM 可能会在未来的某个时间点自动进行优化,但这不是显式控制的过程。

加深记忆的例子

想象一下,你住在一个有多间房间的大房子里,每个房间都有一扇门,这些门代表不同的锁状态。

1)无锁到偏向锁:这就像家里的房间通常是开着的,但当你晚上回家并进入你的房间时,你会把门轻轻地关上并转上一圈小锁。这个小锁就是偏向锁,它表示这个房间现在偏向于你,只要你在里面,别人就假设不能进入。但这并不阻止家里的其他人敲门。

2)偏向锁到轻量级锁:如果你的房间门(偏向锁)关着,你的室友想进入时,他们会敲门。这时,你意识到需要更多的隐私,于是你会起来,从里面用钥匙把门锁上,然后再打开让室友进来。这个上锁的动作就像是轻量级锁的获取,需要更明确的操作(比如 CAS 操作)来确保门的状态。

3)轻量级锁到重量级锁:如果你的房间里正在举行派对,很多人想进来,但门只能让一个人一次进入。于是你决定使用门卫(监视器锁),让他决定谁能进来,谁需要等待。这时,门的锁就升级成了重量级锁,确保了同一时间只有一个人可以进入房间,其他人需要在外面等候。

锁的升级与降级

1)锁升级:这个过程就像是门的锁从一个简单的转把锁(偏向锁),到需要钥匙才能打开的锁(轻量级锁),再到需要门卫控制的高级锁系统(重量级锁)。随着需要控制的人数增多,门的锁系统也变得更加复杂和安全。

2)锁降级:在 Java 中,锁的降级不常见,因为一旦使用了重量级锁,系统就倾向于保持这种状态。但如果将其比喻到现实生活中,可以想象在一天结束时,派对结束了,你告诉门卫他可以回家了,然后你自己使用钥匙锁上门,最终可能只是简单地关上门而不上锁,这就相当于锁的状态从重量级锁“降级”回到了更轻量的状态。

 

JVM中的锁优化技术

除了已提及的偏向锁、轻量级锁和重量级锁,JVM在运行时还会采用如下几种技术进一步优化锁的性能:

  1. 锁粗化(Lock Coarsening):如果 JVM 检测到一系列的连续锁获取和释放操作,且都是对同一个对象,那么 JVM 会尝试合并这些操作,扩大锁的范围,从而减少锁获取和释放的次数。这种优化通常发生在循环中对同一个对象进行加锁的场景。

  2. 锁消除(Lock Elimination):JVM 在 JIT 编译阶段通过逃逸分析来判断同步代码块是否可能被多线程访问。如果一个对象不会逃逸出当前线程,那么对这个对象的同步操作实际上是不必要的,因此 JVM 可以安全地消除这部分代码的锁操作。

优化策略

JVM 采用了多种优化策略来减少锁操作的开销,例如锁粗化(Lock Coarsening)、锁消除(Lock Elimination)和自旋锁等。这些优化旨在减少不必要的锁竞争开销,提高多线程程序的执行效率。

  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值