Java监视器有多重?


问题内容

假设我有成千上万个对象的数组,还有少量线程可以访问每个对象。我想保护对一种对象方法的访问。最简单的方法是将该方法声明为synchronized。但是,无论采用哪种实施方式,这都可能导致创建数千个监视器。如果这是Win32,我将永远不会创建数千个内核对象(例如Mutex),但是CRITICAL_SECTIONs
可能
是合理的。我想知道Java中的情况如何。考虑到争用的机会很低,使用监视器会带来比其所需的过多内存更多的负担吗?在Java中使用这种低粒度同步有多普遍?

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


问题答案:

您已经为使用Java配备Monitors付出了(大部分且争夺性很低)的惩罚……没有理由不使用它们。特别是在低竞争的情况下,它们非常便宜(请参阅此处的项目2.1、2.2、2.3此处的项目#1),JVM可以在许多情况下完全优化它们。如果仅暂时使用对象的监视器,则JVM将使其变得“足够大”(这意味着它以位翻转开始,对于简单的争用情况可能会扩展为堆栈分配的原子标志,并且在持久争用下为该对象分配了对象监视器它;所有这些将在争用减少时退回到低开销的情况),并在以后收回空间。就这些对象上的锁定而言,在应用程序方面是“正确的事情”,我会说。

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

演示文稿由Dave骰子给出了一些有益的见解的Java6同步是如何工作的,这博客条目是同步的Java的信息宝库。如果您真的很在乎一个完整的对象监视器结构有多“大”(在有争议的情况下会起作用),请参见此处代码。HotSpot内部Wiki页面也提供了一些很好的深入信息