繁体   English   中英

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

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

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

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

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

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

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

你永远不能确定一个对象永远不会被用作锁(考虑反射)。 通常,每个对象都有一个标题,其中一些位专用于锁。 可以实现它,以便只根据需要添加标头,但这有点复杂,你可能还需要一些标头(类(相当于“vtbl”和C ++中的分配大小),哈希代码和垃圾收集) 。

这是一个关于OpenJDK中同步实现的维基页面。

(在我看来,为每个对象添加锁是一个错误。)

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

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

JVM不能直接使用比较和交换指令吗? 假设每个对象都有一个字段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

这是一个玩具模型,但它似乎并不太昂贵,并且不依赖于操作系统。

暂无
暂无

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

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