Java监视器有多重?

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

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

你已经支付了(大部分,并且在低争用中)使用Java监视器的惩罚…没有意义不使用它们。 特别是在低竞争情况下,它们非常便宜(参见此处的项目2.1,2.2,2.3和此处的 项目#1 ),并且JVM可以针对许多情况完全优化它们。 如果你只是暂时使用对象的监视器,那么JVM会使它“足够大”(意味着它从位翻转开始,可能会因为简单的争用情况而扩展到堆栈分配的primefaces标志,并且在持久争用下会分配一个objectmonitor)它;当争用减少时,所有这些都将被展开回到低开销的情况下)并且稍后回收空间。 如果锁定这些对象是应用程序方面的“正确的东西”,我会说它去做。

但是,这里有一种设计气味。 锁定这么多物体听起来不太好。 此外,如果您有任何顺序锁定条件,您将无法推断潜在的死锁。 我建议你用关于应用程序的更多细节来增加你的问题,我们可以问一下锁定大型对象池是否正确。

Dave Dice的这个演示提供了一些有用的见解,了解Java6同步的工作原理,这篇博客文章是Java信息同步的宝库 。 如果你真的非常关心一个完整的对象监视器结构是多么“大”(将在竞争情况下发挥作用), 代码就在这里 。 HotSpot内部维基页面也有一些很好的深入信息 。

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

在非竞争情况下,Java互斥体仅包含标志字中的2位。 当互斥锁争用时,JVM仅将重量级OS锁定对象与Java互斥锁关联,然后在所有线程退出互斥锁时释放操作系统锁定。

有关如何实现Java互斥体的概述可以在Javaone 2006 演示文稿的幻灯片9到23中找到。


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

  • 在Java早期版本中,互斥量明显更高。
  • 自JavaOne 2006论文以来,可能已经取得了一些进展……是否已经发表。

我认为Collections.synchronizedCollection让一个线程访问该集合。 但是存在创建监视器的问题。