Java 已移除偏向锁 - 会影响您吗?
上周我们得知,Java 15 中的 OpenJDK 团队已在 Java 虚拟机中禁用了偏向锁(JEP 374)。与之前的版本相比,这一更改可能会对 Java 应用程序的性能产生负面影响。
Red Hat 自家的性能团队目前正在进行性能测试,以了解它对我们的 Java 中间件有何影响,但任何泛泛的测试都无法揭示此更改对真实世界应用程序的影响。
这时就需要您了。
我们希望从您那里获取有关您的应用程序性能是否受偏向锁影响的信息。
为此,请在您的应用程序性能测试中尝试以下操作:
使用 Java 11 (jdk11u),如果可行,也使用 Java 15 (jdk15),并添加以下命令行标志来像往常一样运行您的 Quarkus 应用程序性能测试:
启用:-XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0
禁用:-XX:-UseBiasedLocking
我们希望了解本次测试的结果,无论您是在相同的 Java 虚拟机上看到回归还是没有。
如果可能,使用以下场景运行它也会有很大帮助:
-
单线程
-
线程数 ~= 硬件核心数
-
线程数 ~= N * 硬件核心数,其中 8 < N < 16
这些场景的目的是查看并发级别如何影响结果。
报告结果
请打开一个 bug,在标题中包含 [jep374]
+ 您的项目。例如:[jep374] acme 项目 crazy panda 的结果
,并在描述中按每次运行提供以下信息:
jvm used: jdk11 or jdk15
thread-count: 1..N (if you know)
hardware-core count: N (if you know)
performance test result: with biased locking
performance test result: without biased locking
这将极大地帮助我们。谢谢!
背景
以下是一些关于偏向锁的背景信息 - 均可选阅读 - 您无需了解细节即可通过运行性能测试并告知我们是否有任何变化来帮助我们。
什么是偏向锁?
偏向锁降低了/无竞争/同步的成本。
没有偏向锁:当一个线程对同一个对象执行重复同步时,它需要设置和清除锁位。它还需要等待这些设置/清除写入本地缓存后再继续执行其他内存操作。
有偏向锁:当一个线程首次同步一个对象时,它会做更多的工作来获取同步(将其“偏向”于该线程)。后续的同步通过简单的读取测试进行,无需刷新到缓存。
那么权衡是什么呢?好吧,如果偏向锁存在竞争,那么偏向和解除偏向锁的工作量就会更大。然而,众所周知,许多同步操作是没有竞争的。
当一个潜在的并发数据结构实际上是顺序使用时,偏向可以带来巨大的好处。它最有帮助的例子就是我们在 DataOutputStream
类中发现的问题。通常只有一个线程写入 DataOutputStream
,并且在流填满之前通常不会被读取。尽管如此,每次调用 putInt()
或 putLong()
都会调用同步方法来将字节计数增加 4 或 8。这是必要的,以防万一其他线程想要可靠地定位有效缓冲区数据的末尾,但这很少发生。因此,无偏向的情况在每次基本 put 操作中都会遭受锁写入和缓存刷新延迟。
ByteOutputStream
类也出现了类似的情况。putByte
方法是同步的。因此,写入单个字节涉及锁定和解锁。请注意,putInt
方法调用 putByte
4 次,需要 4 次锁定和解锁。putLong
调用它 8 次!