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