这是一个老生常谈的面试题了,wait
和 notify
配合监视器提供了多个同步线程之间通信机制,答案本身也很简单,由于通信本身解决的就是锁的归属问题(发现当前应该把锁给别人时调用 wait
, 通知别人可以来用锁了调用 notify
),从功能上讲,放在 Object
类(锁对象)中本就是理所当然的。
但我们可以换个角度去思考,不妨使用假设法,假设 wait
和 notify
是放在 Thread
类中,看看使用的情况会是怎么样的。
由于线程之间并不知道其他对象获取锁的情况,需要额外的开销去记录和遍历其他线程的情况,并且一个线程实际上是可以拥有多个锁的。因此,要实现线程通信机制,有两个必不可少的参数,线程和锁对象。
synchronized(lock) {
Thread.currentThread().wait(lock);
}
如果是这么使用的话其实没有什么问题,从功能上来说其实和 lock.wait()
没有什么区别。但是,只要有存在的可能,就一定会发生。有些人可能刚好由于契合某些业务来实现某些功能会写出以下代码:
List<Thread> threadList = ...
synchronized(lock) {
threadList.get(i).wait(lock);
}
在当前线程的代码允许其他的线程在所需的锁上等待,这种“入侵”式的代码给设计和维护带来了许多的困难,原本并发程序就不好调式,这样一来就更加的混乱,并且产生无法预计和复现的错误。毕竟可能让使用者产生错误用法的设计就不是一个好的设计。