如何在 OpenJDK 中禁用自旋锁以进行同步

How to disable the spinlock for synchronization in OpenJDK

背景

我正在 AdoptOpen运行 上分析 Java servlet 运行 的性能问题JDK 11. 随着并发请求数量的增加,servlet 的响应时间变慢。

为了找出问题的原因,我在更改并发请求数时使用两个工具收集了性能信息:

问题

根据 Mission Control,servlet 存在同步问题。当两个或多个请求并发时,它会导致如此多的同步事件。同步事件在用于查找 table 的 class 中触发。查找 table 是用 ConcurrentHashMap 实现的。所以同步不是有意的,看起来没有必要。

另一方面,根据性能监视器,并发请求数和 CPU 使用率百分比几乎呈线性增长。这是我意想不到的结果。

我原以为 CPU 使用会变得恒定,因为由于同步,请求将一个一个地处理。作为更多研究的结果,我发现 Java VM 引入了 the Adaptive Spinning on Java 6,并且我假设这个(Java VM 中用于同步的自旋锁)是为什么CPU 使用率线性增加。

问题

导致同步问题的class在我们的应用程序中用了很多地方。为了对 class 的更改进行推理和解释(从 class 中删除 synchronized 块),我必须用性能测试的结果来确认假设。为了证实这个假设,我想在 Java VM 中禁用同步自旋锁。

我发现 JRockit and OpenJ9 有命令行选项可以改变自适应旋转的行为。但是我找不到 OpenJDK 的等效项。 java -XX:+PrintFlagsFinal -version.

的结果中没有与自旋锁相关的选项

有没有办法在 OpenJDK Java VM 中禁用自旋锁同步?

问题实际上是XY problem。我会以实验可能无用甚至误导的警告来回答它。

禁用旋转会减少 CPU 使用率的假设不一定正确。如果不旋转,争用锁最终会调用 OS 内核到 park/unpark 线程。具有上下文切换的系统调用是昂贵的,因此,根据线程数和临界区的长度,这实际上可能 增加 CPU 使用率。

在 OpenJDK11 中禁用内部锁自旋的选项是:

-XX:+UnlockExperimentalVMOptions -XX:SyncKnobs=SpinLimit=0:SpinBase=0:PreSpin=0:SpinEarly=0

然而,SyncKnobs 从未被发现有用,并且 completely removed 在 JDK 12.