Java监视器有多重?

2022-09-03 13:58:28

假设我有一个包含数千个对象的数组,以及可能访问每个对象的少量线程。我想保护对其中一个对象方法的访问。最简单的方法是将该方法声明为 。但是,这可能会导致创建数千个监视器,无论它们以何种方式实现。如果这是Win32,我永远不会创建数千个内核对象,如Mutex,但CRITICAL_SECTIONs可能是合理的。我想知道Java中的情况如何。鉴于争用的可能性很低,使用监视器是否会施加超过它们所需的内存量?在Java中使用这种低粒度同步的做法有多普遍?synchronized

(显然有一些解决方法,例如使用更小的同步对象数组,这些对象将使用一些哈希进行访问。我不是在寻找一个实用的解决方案,我正在寻找一个洞察力)。


答案 1

您已经支付了(大部分,并且在低争议中)通过使用Java来拥有监视器的惩罚...没有意义不使用它们。特别是在低争用的情况下,它们非常便宜(请参阅此处的项目2.1,2.2,2.3此处的项目#1),并且JVM可以针对许多情况完全优化它们。如果您只是暂时使用对象的监视器,JVM 将使其“足够大”(这意味着它从位翻转开始,可能会扩展到简单的争用情况到堆栈分配的原子标志,并且在持久争用下为其分配一个对象监视器;随着争用的减少,所有这些都将展开回低开销情况),并在以后回收空间。在某种程度上,锁定这些对象在应用程序方面是“正确的事情”,我会说去吧。

但是,这里有一种设计气味。锁定这么多对象听起来并不好。此外,如果您有任何顺序锁定条件,您将无法推理潜在的死锁。我建议您用有关应用程序的更多详细信息来补充您的问题,我们可以询问锁定大型对象池是否正确。

Dave Dice 的这个演讲为 Java6 同步的工作原理提供了一些有用的见解,这篇博客文章是 Java 上同步信息的宝库。如果你真的,真的关心一个完整的objectmonitor结构有多“大”(在有争议的情况下会发挥作用),代码就在这里。HotSpot内部wiki页面也有一些很好的深入信息


答案 2

Java互斥体足够便宜,你可以拥有数十万个同步对象而不会注意到它。

在未扩展的情况下,Java 互斥体在标志词中仅包含 2 位。JVM 仅在争用某个重度操作系统锁对象与 Java 互斥体时将该互斥体关联,然后在所有线程都已退出该互斥体时释放该互斥体。

有关如何实现 Java 互斥锁的概述,请参阅 Javaone 2006 演示的幻灯片 9 到 23。


请注意,互斥锁的实现和性能可能取决于您使用的 Java 的供应商/发行版以及您正在运行的平台。

  • 在早期的Java版本中,互斥锁要昂贵得多。
  • 自JavaOne 2006论文以来,可能已经取得了进展......是否发布。

推荐