JVM 是否为每个对象创建一个互斥锁以实现“同步"关键字?如果没有,怎么办?

2022-01-16 00:00:00 jvm implementation synchronization c++ java

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

As a C++ programmer becoming more familiar with Java, it's a little odd to me to see language level support for locking on arbitrary objects without any kind of declaration that the object supports such locking. Creating mutexes for every object seems like a heavy cost to be automatically opted into. Besides memory usage, mutexes are an OS limited resource on some platforms. You could spin lock if mutexes aren't available but the performance characteristics of that are significantly different, which I would expect to hurt predictability.

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

Is the JVM smart enough in all cases to recognize that a particular object will never be the target of the synchronized keyword and thus avoid creating the mutex? The mutexes could be created lazily, but that poses a bootstrapping problem that itself necessitates a mutex, and even if that were worked around I assume there's still going to be some overhead for tracking whether a mutex has already been created or not. So I assume if such an optimization is possible, it must be done at compile time or startup. In C++ such an optimization would not be possible due to the compilation model (you couldn't know if the lock for an object was going to be used across library boundaries), but I don't know enough about Java's compilation and linking to know if the same limitations apply.

推荐答案

作为一个看过一些 JVM 实现锁的方式的人来说......

Speaking as someone who has looked at the way that some JVMs implement locks ...

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

The normal approach is to start out with a couple of reserved bits in the object's header word. If the object is never locked, or if it is locked but there is no contention it stays that way. If and when contention occurs on a locked object, the JVM inflates the lock into a full-blown mutex data structure, and it stays that way for the lifetime of the object.

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

EDIT - I just noticed that the OP was talking about OS-supported mutexes. In the examples that I've looked at, the uninflated mutexes were implemented directly using CAS instructions and the like, rather than using pthread library functions, etc.

相关文章