JVM 是否为每个对象创建一个互斥体以实现 “synchronized” 关键字?如果没有,如何?

2022-09-02 10:26:01

作为一名C++程序员越来越熟悉Java,对我来说,看到语言级支持锁定任意对象而没有任何类型的声明来支持这种锁定,这对我来说有点奇怪。为每个对象创建互斥体似乎是一个沉重的成本,可以自动选择加入。除了内存使用之外,在某些平台上,互斥锁是操作系统有限的资源。如果互斥锁不可用,则可以旋转锁定,但其性能特征明显不同,我认为这会损害可预测性。

JVM 是否在所有情况下都足够智能,可以识别出特定对象永远不会成为同步关键字的目标,从而避免创建互斥锁?互斥体可以懒惰地创建,但这会带来一个引导问题,它本身就需要一个互斥体,即使解决了这个问题,我认为仍然有一些开销来跟踪互斥体是否已经创建。因此,我假设如果这种优化是可能的,则必须在编译时或启动时完成。C++由于编译模型的原因,这样的优化是不可能的(你无法知道对象的锁是否会跨库边界使用),但我对Java的编译和链接的了解还不够多,无法知道是否适用相同的限制。


答案 1

作为一个已经研究了一些JVM实现锁的方式的人......

通常的方法是从对象的标头字中的几个保留位开始。如果对象从未被锁定,或者如果它被锁定但没有争用,它将保持这种状态。如果锁定对象上发生争用,JVM 会将锁膨胀为成熟的互斥数据结构,并在对象的生存期内保持这种状态。

编辑 - 我刚刚注意到OP正在谈论操作系统支持的互斥锁。在我看过的示例中,未充气的互斥体是使用 CAS 指令等直接实现的,而不是使用 pthread 库函数等。


答案 2

这实际上是 JVM 的实现细节,不同的 JVM 可能会以不同的方式实现它。但是,它绝对不是可以在编译时优化的东西,因为Java在运行时链接,并且以前未知的代码可以获取在旧代码中创建的对象并开始在其上进行同步。

请注意,在 Java 术语中,同步原语称为“monitor”而不是互斥体,并且它由特殊的字节码操作支持。这里有一个相当详细的解释。


推荐