出于好奇,当Java实现wait()和notify()方法时,它们真的只是使用锁吗?即,wait() 获取一个互斥量,notify() 释放一个互斥量,notifyAll() 释放所有互斥量(当然是在同一个对象中)?
使用wait()和notify()除了比使用锁更简单之外,还有其他优点吗?
[编辑] 在 Brian 的评论之后,我意识到自己对什么感到困惑:
wait 不加锁,它释放锁并将它传递给正在等待 mutex 的同步语句的其他人,然后等待拥有锁的其他人的通知并调用 notify,后者将锁传回到调用等待的原始线程。我认为这就是你感到困惑的地方。 – 布赖恩 17 分钟前
最佳答案
其他问题集中在语言中 wait
和 notify
是什么 - 但那似乎不是你的问题......你讨论互斥体,这是一个实现细节,因此是特定于 JVM 的。
所以我们需要选择一个 JVM - 让我们选择 openjdk(源可用 here)。在 hotspot/src/share/vm/runtime/objectMonitor.cpp
中可以找到(最终)处理所有这些内容的代码。
这维护了两个数据结构——一个等待集和一个入口集。等待线程被添加到等待集中并停放,而试图占用监视器的线程被添加到入口集然后停放。在 notify
上,从等待集中取出一个线程并添加到入口集中。当线程释放锁时,如果有的话,它会从条目集中取消停放一个线程。请注意,这些集合实际上是作为队列(链表)实现的,因此按照 FIFO 的原则进行处理。
因此,在这种特殊情况下,实现以类似的方式处理等待对象的监视器和尝试获取对象的监视器。
但这只是一个 JVM 的一种实现(尽管其他人可能会做类似的事情)——所以我们不能依赖它。所以我想问题是你为什么想知道?如果只是出于好奇,那么浏览一下 openjdk 代码,它会令人着迷。如果您计划在您的代码中使用此信息……请不要。
更新
我意识到说“公园”并不能告诉我们太多信息。停放线程的代码是特定于平台的(并在名为 PlatformEvent
的对象中实现,该对象是 ParkEvent
的扩展)。在我正在查看 linux 的 park 代码的 openjdk 版本中,可以在 hotspot/src/os/linux/vm/os_linux.cpp
中找到它调用 pthread_mutex_lock(_mutex)
... 所以在回答您的问题时,是调用 wait 可能 在我的机器上 需要一个互斥量。请注意,在此之上还有很多事情可能会阻止我们到达这一点。
关于java - Java wait(), notify() 的实现与锁有很大不同吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17257471/