【发布时间】:2010-12-18 16:13:22
【问题描述】:
为什么wait() 和notify() 方法声明在Object 类中,而不是Thread 类中?
【问题讨论】:
标签: java multithreading wait notify
为什么wait() 和notify() 方法声明在Object 类中,而不是Thread 类中?
【问题讨论】:
标签: java multithreading wait notify
因为,您要等待给定的对象(或具体来说,它的监视器)才能使用此功能。
我认为您可能误解了这些方法的工作原理。它们不只是处于线程粒度级别,即不是只是调用wait() 并被下一次调用notify() 唤醒的情况。相反,您总是在特定对象上调用 wait(),并且只会通过在该对象上调用 notify 来唤醒。
这很好,否则并发原语将无法扩展;这相当于拥有全局命名空间,因为在程序中的任何位置对notify() 的任何调用都可能会弄乱任何并发代码,因为它们会唤醒阻塞在wait() 上的任何线程称呼。因此,您在特定对象上调用它们的原因;它为等待通知对操作提供了上下文,因此当您在私有对象上调用myBlockingObject.notify() 时,您可以确定您只会唤醒类中调用等待方法的线程。某些可能正在等待另一个对象的 Spring 线程不会被此调用唤醒,反之亦然。
编辑:或者从另一个角度解决它 - 我希望从你的问题中你认为你会得到一个等待线程的句柄并在 那个线程 上调用 notify() 来唤醒它。不这样做的原因是你必须自己做很多家务。等待的线程必须在其他线程可以看到的地方发布对自身的引用;这必须适当地同步以加强一致性和可见性。当你想唤醒一个线程时,你必须获取这个引用,唤醒它,然后从你阅读它的任何地方删除它。与仅在睡眠线程中调用 myObj.wait() 然后在唤醒线程中调用 myObj.notify() 相比,涉及更多的手动脚手架,并且出错的可能性更大(尤其是在并发环境中)。
【讨论】:
最简单和最明显的原因是任何对象(不仅仅是一个线程) 可以是线程的监视器。等待和通知在 监视器。正在运行的线程检查监视器。所以wait和notify方法在Object而不是Thread
【讨论】:
因为一次只有一个线程可以拥有一个对象的监视器,而这个监视器是线程正在等待或通知的。如果您阅读了javadoc 中的Object.notify() 和Object.wait(),则会对其进行详细描述。
【讨论】:
同步机制涉及一个概念——对象的监视器。当调用 wait() 时,将请求监视器并暂停进一步的执行,直到获取监视器或发生 InterruptedException。当调用 notify() 时,释放监视器。
假设wait() 和notify() 被放置在Thread 类而不是Object 类中。在代码中的某一时刻,currentThread.wait() 被调用,然后对象 anObject 被访问。
//.........
currentThread.wait();
anObject.setValue(1);
//.........
当 currentThread.wait() 被调用时,currentThread 的监视器被请求,并且在获取监视器或发生 InterruptedException 之前不会进一步执行。现在处于等待状态时,如果从另一个线程调用驻留在currentThread 中的另一个对象anotherObject 的方法foo(),即使被调用的方法foo() 没有访问anObject,它也会卡住。如果在anObject 上调用第一个wait() 方法,而不是线程本身,则对驻留在同一线程中的对象的其他方法调用(不访问anObject)不会卡住。
因此在 Object 类(或其子类)上调用 wait() 和 notify() 方法提供了更高的并发性,这就是为什么这些方法在 Object 类中,而不是在 Thread 类中。
【讨论】:
其他一些答案使用“监视器”一词,但没有人解释它的含义。
“监视器”这个名称早在 1970 年代就被创造出来了,它指的是一个拥有自己的内在锁和相关等待/通知机制的对象。 https://en.wikipedia.org/wiki/Monitor_%28synchronization%29
20 年后,有一个短暂的时刻,台式机、多处理器计算机是新的,流行的想法是为它们设计软件的正确方法是创建面向对象的程序,其中 每个物体都是一个监视器。
事实证明这不是一个有用的想法,但那个短暂的时刻恰好是 Java 编程语言被发明的时候。
【讨论】:
阅读 here 了解等待和通知的说明。
最好在您的应用程序中避免这些,并使用更新的java.util.concurrent 包。
【讨论】:
我会简单地说:
要调用 wait() 或 notify(),您需要拥有对象监视器 - 这意味着 wait() 或 notify() 需要存在于同步块中
synchronized(monitorObj){
monitorObj.wait() or even notify
}
这就是这些方法存在于对象类中的原因
【讨论】:
这是因为,这些方法是用于线程间通信的,线程间通信是通过锁来实现的,但是锁是与对象相关联的,所以它在对象类中。
【讨论】:
Wait 和 Notify 方法用于 Java 中两个线程之间的通信。所以 Object 类是让它们可用于 Java 中的每个对象的正确位置。
另一个原因是每个对象都可以使用锁。线程需要锁,他们等待锁,他们不知道哪些线程持有锁,他们只知道锁被某个线程持有,他们应该等待锁,而不是知道哪个线程在同步块内并要求他们释放锁
【讨论】: