谁能解释线程监视器并等待?

Bil*_*l K 40 java multithreading monitor

工作中的某个人刚刚询问了必须在同步中包装等待的原因.

老实说,我看不出推理.我理解javadocs所说的 - 线程需要成为对象监视器的所有者,但为什么呢?它会阻止哪些问题?(如果它确实是必要的,为什么等待方法不能获得监视器本身?)

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

哦,还有,thread.sleep如何比较?

编辑:很好的答案 - 我真的希望我可以选择不止一个,因为他们都帮助我理解发生了什么.

Ale*_*ler 14

这里有很多好的答案.但是这里只想提一下,在使用wait()时,其他必须做的就是在一个循环中进行它,这取决于你正在等待的情况,以防你看到虚假的唤醒,这在我的经验确实发生过.

要等待其他某个线程将条件更改为true并通知:

synchronized(o) {
  while(! checkCondition()) {
    o.wait();
  }
}
Run Code Online (Sandbox Code Playgroud)

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

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

}


64B*_*Bob 6

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

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

public void doStuffOnThisObject()
Run Code Online (Sandbox Code Playgroud)

以及以下方法:

public void wait()
Run Code Online (Sandbox Code Playgroud)

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

据推测,wait() 方法未同步,因为这可能会造成 Thread 在对象上有多个锁的情况。(有关这方面的更多信息,请参阅Java 语言规范/锁定。)多锁是一个问题,因为 wait() 方法只会撤消一个锁。如果方法是同步的,它将保证只有方法的锁会被撤消,同时仍然保留潜在的外部锁被撤消。这会在代码中产生死锁条件。

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


Rob*_*bin 5

它需要拥有监视器,因为wait()的目的是释放监视器并让其他线程获取监视器来进行自己的处理.这些方法(wait/notify)的目的是协调对两个线程之间的同步代码块的访问,这两个线程需要彼此执行某些功能.这不仅仅是确保对数据结构的访问是线程安全的,而是协调多个线程之间的事件.

一个典型的例子是生产者/消费者案例,其中一个线程将数据推送到队列,另一个线程消耗数据.消费线程总是要求监视器访问队列,但是一旦队列为空,就会释放监视器.然后,当消费者不再处理时,生产者线程将只能访问该线程.一旦它将更多数据推入队列,它将通知消费者线程,因此它可以重新获得监视器并再次访问队列.


Lou*_*nco 5

等待放弃显示器,所以你必须让它放弃.通知也必须有监视器.

你想要这样做的主要原因是确保你从wait()回来时有监视器 - 通常,你使用wait/notify协议来保护一些共享资源,你希望它是安全的等待返回时触摸它.与通知相同 - 通常您正在更改内容然后调用notify() - 您希望拥有监视器,进行更改并调用notify().

如果你做了这样的功能:

public void synchWait() {
   syncronized { wait(); }
}
Run Code Online (Sandbox Code Playgroud)

等待返回时你不会有显示器 - 你可以得到它,但你可能不会得到它.