java - Java wait(), notify() 的实现与锁有很大不同吗?

标签 java multithreading concurrency locking wait

出于好奇,当Java实现wait()和notify()方法时,它们真的只是使用锁吗?即,wait() 获取一个互斥量,notify() 释放一个互斥量,notifyAll() 释放所有互斥量(当然是在同一个对象中)?

使用wait()和notify()除了比使用锁更简单之外,还有其他优点吗?

[编辑] 在 Brian 的评论之后,我意识到自己对什么感到困惑:

wait 不加锁,它释放锁并将它传递给正在等待 mutex 的同步语句的其他人,然后等待拥有锁的其他人的通知并调用 notify,后者将锁传回到调用等待的原始线程。我认为这就是你感到困惑的地方。 – 布赖恩 17 分钟前

最佳答案

其他问题集中在语言中 waitnotify 是什么 - 但那似乎不是你的问题......你讨论互斥体,这是一个实现细节,因此是特定于 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/

相关文章:

Java/IntelliJ 无法识别 Dagger2 组件的 "Dagger"关键字

java - 使用 MockMvcstandaloneSetup 时 MockBean 未初始化服务 bean

java - 没有待处理的回复 : ConsumerRecord

c# - 替代 Thread.Suspend() 方法

ios - Apple 的 Advanced NSOperations 示例代码中的竞争条件

ruby - 为什么 ruby​​ 的单个操作系统线程在复制文件时不会阻塞?

c# - 在多线程场景中从 List<T> 添加/删除特定项目的最佳方法是什么

java - 使用 Java 运行时 psexec 停止

java - 服务器-客户端这里出了什么问题?

dictionary - 如何解决 fatal error : concurrent map read and map write