1. API概述
以下四个方法都是操作「当前对象obj对应的Monitor对象(之后简称 当前对象锁)」中的 Owner 或 WaitSet。
这些方法执行的前提都是当前线程必须持有锁。
| 方法签名 | 功能概述 | 备注 |
|---|
| void Object.wait() | 使当前对象锁中Owner进入WAITING状态 | 当前线程必须要持有锁 |
| void Object.wait(long m) | 使当前对象锁中Owner进入TIMED_WAITING状态 | 当前线程必须要持有锁,m毫秒后会自动唤醒 |
| void Object.notify( ) | 唤醒当前对象锁中WaiSet的随机一个线程 | 当前线程必须要持有锁 |
| void Object.notifyAll( ) | 唤醒当前对象锁中WaiSet的所有线程 | 当前线程必须要持有锁 |
2. obj.wait( ) / obj.wait( long m ) 底层原理:
- [释放锁并进入WaitSet] 调用 obj.wait( ) / obj.wait( long m ) 后,当前对象锁的 Owner 将进入 WaitSet 并进入「WAITING / TIMED_WAITING」状态,此时 Owner 空缺,因此 释放了锁;
- [唤醒EntryList的阻塞线程] 由于 Owner 空缺,根据JVM底层算法,某个EntryList中的线程将被唤醒,并成为新的Owner。

3. 唤醒 WAITING / TIMED_WAITING 线程的三种方式
处于 WaitSet 的线程会在三种情况下会被唤醒,进入到 EntryList 并进入 BLOCKED 状态:
- [自动唤醒] 若线程因调用了 obj.wait( long m ) 而进入了 TIME_WAITING 状态,会在m毫秒后被自动唤醒;
- [随机唤醒] 在调用 obj.notify( ) 后,JVM会将 WaitSet 中 随机一个 线程唤醒;
- [全部唤醒] 在调用 obj.notifyAll( ) 后,JVM会将 WaitSet 的所有线程唤醒。

4. Thread.sleep( long m ) VS obj.wait( long m )
4.1. 相同点
- [状态一致、自动唤醒] sleep( long m ) 与 wait( long m ) 调用后,二者的状态都是TIMED_WAITING,m毫秒后将被自动唤醒;
- [被打断后均会抛出异常] 处于TIMED_WAITING(和WAITING)状态的线程被打断后都会抛出异常,并将标识重置为false。
4.2. 不同点
- [静态vs非静态] Thread.sleep( long m ) 是一个静态方法,而 obj.wait( long m) 是Object类的成员方法,这意味着这个obj对应的 Monitor 对象必须要有 Owner;
- [是否释放锁] sleep( long m ) 调用后仍为Owner(不释放锁),wait( long m ) 调用后则是让自己从 Owner 进入到 WaitSet(释放了锁);
- [wait有无参方法] 无参方法 wait( ) 调用后将进入WAITING状态,只能被打断或被nodify( ) / nodifyAll( )唤醒;
参考资料
[视频] 04.039-小故事-wait-notify
[视频] 04.040-wait-notify-工作原理
[视频] 04.041-wait-notify-api1
[视频] 04.042-wait-notify-api2
[视频] 04.043-wait vs sleep