8

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

除了比使用锁更方便之外,使用wait()和notify()还有其他好处吗?

[编辑] 在布赖恩发表评论后,我意识到自己对什么感到困惑:

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

4

5 回答 5

13

其他问题集中在语言所说的waitnotify是什么上——但这似乎不是你的问题……你谈论的是互斥体,这是一个实现细节,因此是特定于 JVM 的。

所以我们需要选择一个 JVM——让我们选择 openjdk(源代码在这里)。(最终)处理所有这些东西的代码位在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可能在我的机器上使用互斥锁。请注意,在此之上会发生很多事情,这可能会阻止我们到达这一点。

于 2013-06-27T07:53:10.623 回答
4

wait()并且notify()不要进行任何监视器采集。正如这些方法的 javadoc 所述,调用者必须在调用之前获取监视器。事实上,wait()实际上释放了调用者获取的监视器(虽然,我想技术上等待确实在最终返回之前执行监视器(重新)获取)。

于 2013-06-23T03:32:23.217 回答
1

wait释放您已经拥有的锁,以便在其他人调用notify. 这是对 提供的锁定机制的补充synchronized。基本上,您使用synchronized获取锁,然后使用wait,notifynotifyAll控制这些锁的释放和重新锁定方式。

于 2013-06-23T03:34:10.943 回答
1

wait()notify()始终与 Synchronization 一起工作,因此可以在 Locks 和同步之间进行比较。RentrantLock、ReadWriteLock 和 Synchronization [block, methods] 等锁之间存在很大差异。

  1. 锁在内部不使用同步wait(),而notify()需要同步。

  2. 您将 Lock 与 java.util.concurrent.locks.Condition 一起使用,它可以有效地启用条件锁定,这对于同步实现来说非常繁琐。

  3. 您没有任何带有同步的 tryLock 选项,您要么锁定,要么等待。但是使用 Lock 界面,您可以选择。

于 2013-06-23T03:34:14.830 回答
1

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

抱歉,但这些都不对。:)

  • 它是synchronized获得monitor. 即这是一种锁定形式。注意: usingjava.util.concurrent.locks.Lock做类似的事情。
  • wait()导致当前线程等待,直到另一个线程调用该notify()方法或notifyAll()该对象的方法,或者经过了指定的时间量。与锁定无关 - 但只能在当前线程当前线程已经拥有此对象的监视器时调用此方法(在synchronized块/方法中)
  • notify()唤醒正在此对象的监视器上等待的单个线程。同样,与锁定无关 - 但只能在当前线程当前线程已经拥有该对象的监视器时调用此方法(在synchronized块/方法中)
于 2013-06-23T03:39:25.373 回答