任何人都可以解释线程监视器并等待吗?

2022-09-01 02:10:48

有人在工作中只是询问了必须将等待包装在同步中的原因。

老实说,我看不出其中的道理。我理解javadocs所说的 - 线程需要成为对象监视器的所有者,但为什么呢?它可以防止哪些问题?(如果确实有必要,为什么等待方法不能获取监视器本身?

我正在寻找一个相当深入的原因,或者可能是对一篇文章的引用。我在快速的谷歌中找不到一个。

哦,另外,thread.sleep如何比较?

编辑:一套很棒的答案 - 我真的希望我能选择不止一个,因为它们都帮助我了解发生了什么。


答案 1

这里已经有很多好的答案了。但在这里只想提一下,使用wait()时必须做的另一件事是在循环中执行此操作,这取决于您正在等待的条件,以防万一您看到虚假的唤醒,根据我的经验,这种情况确实会发生。

要等待其他线程将条件更改为 true 并通知,请执行以下操作:

synchronized(o) {
  while(! checkCondition()) {
    o.wait();
  }
}

当然,现在,我建议只使用新的 Condition 对象,因为它更清晰,并且具有更多功能(例如允许每个锁的多个条件,能够检查等待队列长度,更灵活的计划/中断等)。

 Lock lock = new ReentrantLock();
 Condition condition = lock.newCondition();
 lock.lock();
 try {
   while (! checkCondition()) {
     condition.await();
   }
 } finally {
   lock.unlock();
 }

}


答案 2

如果对象在调用 Object.wait() 时不拥有对象监视器,则在释放监视器之前,它将无法访问该对象以设置通知侦听器。相反,它将被视为尝试访问同步对象上的方法的线程。

或者换句话说,两者之间没有区别:

public void doStuffOnThisObject()

和以下方法:

public void wait()

在释放对象监视器之前,这两种方法都将被阻止。这是 Java 中的一项功能,用于防止多个线程更新对象的状态。它只是对 wait() 方法产生了意想不到的后果。

据推测,wait() 方法不同步,因为这可能会导致 Thread 在对象上有多个锁的情况。(有关此内容的更多信息,请参阅 Java 语言规范/锁定。多个锁是一个问题,因为 wait() 方法只会撤消一个锁。如果该方法已同步,它将保证只有该方法的锁定将被撤消,同时仍然使潜在的外部锁定被撤消。这将在代码中创建死锁条件。

要回答您在Thread.sleep()上的问题,Thread.sleep()不保证您等待的任何条件都已得到满足。使用 Object.wait() 和 Object.notify() 允许程序员手动实现阻塞。一旦发送满足条件的通知,线程将取消阻止。例如,从磁盘读取已完成,数据可以由线程处理。Thread.sleep() 将要求程序员轮询是否满足条件,然后如果尚未满足,则回退到睡眠状态。