Java 中的 synchronized 轻量级锁是否会进行自旋?

Sherwin.Wei Lv7

Java 中的 synchronized 轻量级锁是否会进行自旋?

回答重点

轻量级锁 CAS 失败了之后,不会有自旋操作,会直接进入重量级锁膨胀过程。

扩展知识

关于 Synchronized 专门翻阅 JVM HotSpot 1.8 的源码来研究了了,那时候就发现有一个点,一个几乎网上所有文章包括《Java并发编程的艺术》也是这样说的一个点。

Snipaste_2024-04-30_20-32-15.jpg

锁升级想必网上有太多文章说过了,这里提到当轻量级锁 CAS 失败,则当前线程会尝试使用自旋来获取锁。

其实起初我也是这样认为的,毕竟都是这样说的,而且也很有道理。

因为重量级锁会阻塞线程,所以如果加锁的代码执行的非常快,那么稍微自旋一会儿其他线程就不需要锁了,就可以直接 CAS 成功了,因此不用阻塞了线程然后再唤醒。

但是我看了源码之后发现并不是这样的,这段代码在 synchronizer.cpp 中。

691.webp

所以 CAS 失败了之后,并没有什么自旋操作,如果 CAS 成功就直接 return 了,如果失败会执行下面的锁膨胀方法。

我去锁膨胀的代码ObjectSynchronizer::inflate翻了翻,也没看到自旋操作。

所以从源码来看轻量级锁 CAS 失败并不会自旋而是直接膨胀成重量级锁。

不过为了优化性能,自旋操作在 Synchronized 中确实却有。

那是在已经升级成重量级锁之后,线程如果没有争抢到锁,会进行一段自旋等待锁的释放。

咱们还是看源码说话,单单注释其实就已经说得很清楚了:

709.webp

毕竟阻塞线程入队再唤醒开销还是有点大的。

我们再来看看 TrySpin 的操作,这里面有自适应自旋,其实从实际函数名就 TrySpin_VaryDuration 就可以反映出自旋是变化的。

710.webp

至此,有关 Synchronized 自旋问题就完结了,重量级锁竞争失败会有自旋操作,轻量级锁没有这个动作(至少 1.8 源码是这样的)

Comments
On this page
Java 中的 synchronized 轻量级锁是否会进行自旋?