为什么同步关键字在 Java 中很慢




最近我和一个朋友讨论了java中的并发性,他问我为什么同步关键字要么围绕代码块要么慢。我回答说它很慢,因为它争用对象监视器。此外,它还在保证之前发生,并且必须将其缓存中的所有变量与主内存同步,并且在块结束时,它必须将缓存刷新回来。它还可以防止编译器以及指令的 CPU 重新排序。然而,他说这些确实会导致速度放缓,但这不是性能下降的主要原因。本质上,即使线程命中同步块时没有争用,它也从用户模式切换到内核模式,线程必须保存状态,然后当它离开块时,它必须再次重新加载状态。我试图在网上找到描述这一点的文献,但我找不到任何文献。我想知道是否有人可以确认这是正确的?为什么 java 线程在达到同步时应该进入内核模式,为什么不在此之前?这与此链接中提出的问题不同,因为我询问的是从用户模式到内核模式的显式切换,这会导致性能下降?

你的朋友说的绝对不正确。

你对同步的昂贵之处说得差不多是对的。最困难的部分实际上是(特别是在x86/x86_64处理器上)比较和交换指令,该指令比较并将当前线程设置为锁的所有者。在x86/x86_64 cmpxchg指令用于此,当它到达主内存时,它比任何常规指令都慢。然后,正如您提到的,内存屏障会减慢缓存的速度。

在其他一些架构上,特别是基于RISC的架构上,通常使用被动负载独占/存储独占,这通常要快得多。因此,这可能因架构而异。

无论如何,Java(和任何其他语言)试图避免进入内核,大多数mutext实现只有在几次重试后才会这样做,当几乎很明显线程需要暂停时。

最新更新