简体   繁体   English

JVM是否为每个对象创建一个互斥锁以实现'synchronized'关键字?如果没有,怎么样?

[英]Does the JVM create a mutex for every object in order to implement the 'synchronized' keyword? If not, how?

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. 作为一个越来越熟悉Java的C ++程序员,看到语言级别支持锁定任意对象而没有任何声明对象支持这种锁定,这有点奇怪。 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. 除了内存使用,互斥体在某些平台上是OS有限的资源。 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. 如果互斥锁不可用但你的性能特征明显不同,你可以旋转锁定,我希望这会损害可预测性。

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? 在所有情况下,JVM是否足够智能以识别特定对象永远不会成为synchronized关键字的目标,从而避免创建互斥锁? 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. 在C ++中,由于编译模型这样的优化是不可能的(你不知道对象的锁是否会跨库边界使用),但我对Java的编译和链接知道不够了解如果适用相同的限制。

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. 如果在锁定对象上发生争用,JVM 会将锁定膨胀为完整的互斥锁数据结构,并且在对象的生命周期内保持这种状态。

EDIT - I just noticed that the OP was talking about OS-supported mutexes. 编辑 - 我刚刚注意到OP正在谈论操作系统支持的互斥锁。 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. 在我看过的例子中,未充气的互斥体是使用CAS指令等直接实现的,而不是使用pthread库函数等。

You can never be sure that an object will never be used as a lock (consider reflection). 你永远不能确定一个对象永远不会被用作锁(考虑反射)。 Typically every object has a header with some bits dedicated to the lock. 通常,每个对象都有一个标题,其中一些位专用于锁。 It is possible to implement it such that the header is only added as needed, but that gets a bit complicated and you probably need some header anyway (class (equivalent of "vtbl" and allocation size in C++), hash code and garbage collection). 可以实现它,以便只根据需要添加标头,但这有点复杂,你可能还需要一些标头(类(相当于“vtbl”和C ++中的分配大小),哈希代码和垃圾收集) 。

Here's a wiki page on the implementation of synchronisation in the OpenJDK. 这是一个关于OpenJDK中同步实现的维基页面。

(In my opinion, adding a lock to every object was a mistake.) (在我看来,为每个对象添加锁是一个错误。)

This is really an implementation detail of the JVM, and different JVMs may implement it differently. 这实际上是JVM的实现细节,不同的JVM可能以不同的方式实现它。 However, it is definitely not something that can be optimized at compile time, since Java links at runtime, and this it is possible for previously unknown code to get a hold of an object created in older code and start synchronizing on it. 但是,它肯定不是可以在编译时优化的东西,因为Java在运行时链接,并且这可能使以前未知的代码保持在旧代码中创建的对象并开始在其上进行同步。

Note that in Java lingo, the synchronization primitive is called "monitor" rather than mutex, and it is supported by special bytecode operations. 请注意,在Java术语中,同步原语称为“监视器”而不是互斥,并且它由特殊字节码操作支持。 There's a rather detailed explanation here . 有一个比较详细的解释在这里

can't JVM use compare-and-swap instruction directly? JVM不能直接使用比较和交换指令吗? let's say each object has a field lockingThreadId storing the id of the thread that is locking it, 假设每个对象都有一个字段lockingThreadId用于存储锁定它的线程的id,

while( compare_and_swap (obj.lockingThreadId, null, thisThreadId) != thisTheadId )
    // failed, someone else got it
    mark this thread as waiting on obj.
    shelf this thead

//out of loop. now this thread locked the object

do the work

obj.lockingThreadId = null;
wake up threads waiting on the obj

this is a toy model, but it doesn't seem too expensive, and does no rely on OS. 这是一个玩具模型,但它似乎并不太昂贵,并且不依赖于操作系统。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM