Java 监视器有多重?

2022-01-22 00:00:00 performance synchronization java monitor

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

Say I have an array of thousands of objects, and a small number of threads that might access each of the objects. I want to protect the access to one of the objects methods. Easiest way would be to declare that method as synchronized. However, that might result in creating thousands of monitors, whichever way they are implemented. If this were Win32, I'd never create thousands of kernel objects such as Mutex, but CRITICAL_SECTIONs might be plausible. I'm wondering what's the case in Java. Given the chance of contention is low, would the use of monitors impose more than the sheer amount of memory they require? How common a practice is it to use such low granularity synchronization in Java?

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

(There are obviously workarounds such as using a much smaller array of synchronization objects, which will be accessed using some hash. I'm not looking for a practical solution, I'm looking for an insight).

推荐答案

你已经支付了(大部分,并且在低争用中)使用 Java 让 Monitors 出现的惩罚......不使用它们毫无意义.特别是在低争用情况下,它们非常便宜(参见 Items 2.1, 2.2, 2.3这里和Item #1 here),JVM可以优化它们在一些情况下完全离开.如果您只暂时使用对象的监视器,JVM 将使其足够大"(这意味着它以位翻转开始,可能会针对简单的争用情况扩展为堆栈分配的原子标志,并且在持续争用下分配一个 objectmonitor它;随着争用的减弱,所有这些都将展开回低开销案例)并稍后回收空间.在某种程度上锁定这些对象是应用程序端的正确的事情",我会说去吧.

You have already paid (most of, and in low-contention) the penalty for having the Monitors around by using Java... no sense not using them. Particularly in the low-contention case, they are very cheap (see Items 2.1, 2.2, 2.3 here and Item #1 here), and the JVM can optimize them away entirely for a number of cases. If you only use the object's monitor transiently, the JVM will make it "big enough" (meaning it begins as bit-flipping, might expand for simple contention cases to a stack-allocated atomic flag, and under persistent contention have a objectmonitor allocated for it; all of these will be unrolled back to the low-overhead case as contention abates) and reclaim the space later. To the extent that locking on these objects is the "right thing" on the application side, I'd say go for it.

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

However, there's a design smell here. Locking on so many objects doesn't sound great. Furthermore, if you have any sequential locking conditions, you're not going to be able to reason about potential deadlocks. I suggest you augment your question with more detail about the application, and we can ask whether locking on a large pool of objects is the Right Thing.

这个 Dave Dice 的演示文稿 对 Java6 同步的工作原理提供了一些有用的见解,而这个 博客条目是 Java 同步信息的宝库.如果你真的非常关心一个完整的 objectmonitor 结构有多大"(将在有争议的情况下发挥作用),代码在这里.HotSpot internals wiki 页面也有一些很好的深入信息.

This presentation by Dave Dice gives some useful insight into how Java6 synchronization works, and this blog entry is a treasure trove of sync-on-Java information. If you really, really care about how "big" a full-on objectmonitor structure is (will come into play in the contended case), the code is here. The HotSpot internals wiki page also has some good in-depth information.

相关文章