wait / notify原理
Monitor 中有三个部分:Owner,EntrySet 和 WaitSet。
Owner 是拥有锁的线程地址,EntrySet 是其他线程想要获取锁的列表,WaitSet 是拥有锁的线程一些条件未满足调用 wait() 方法,进入的WaitSet列表,并且释放锁。
在 EntryList 中的线程状态是 BLOCKED,在 WaitSet 中的线程状态是 WAITING。都不占用 CPU 时间片。
wait()执行过程
拥有锁的线程t0调用
wait()
方法,t0进入 WaitSet 列表,且释放锁,同时 EntryList 中的线程得到锁,得到锁的线程t1可以通过notify()
随机唤醒一个在 WaitSet 里的线程,也可使用notifyAll()
方法唤醒所有线程。被唤醒的线程先执行完wait()
后的代码,再进入 EntryList 列表,等待锁的释放。
关于 wait()的API
- wait(0):释放锁,一直等待,直到被唤醒。
wait(0) 默认就是一直等待
- wait(long n):有时限的等待,到 n 毫秒后结束等待,或是被 notify()
sleep(long n) 和 wait(long n) 的区别
1)sleep 是 Thread 方法,wait 是 Object 方法(所有类的对象都可以调用)
2)sleep 不需要配合 synchronized 使用,但 wait 需要和 synchronized 一起用
3)sleep 在睡眠的同时,不会释放对象锁的,但 wait 在等待的时候会释放对象锁
4)它们的状态都是 TIMED_WAITING(wait() =》WAITING)
wait() 和 notify() 的正确使用姿势:
synchronized(lock) {
while(条件不成立) {
lock.wait();
}
// 干活
}
//另一个线程
synchronized(lock) {
lock.notifyAll();
}
其他API
park 和 unpark
它们是 java.util.concurrent 包下 LockSupport 类中的方法。
// 暂停当前线程
LockSupport.park();
// 恢复某个线程的运行
LockSupport.unpark(暂停线程对象)
与Object 的 wait & notify 相比
- wait,notify 和 notifyAll 必须配合 Object Monitor 一起使用,而 park,unpark 不必
- park & unpark 是以线程为单位来【阻塞】和【唤醒】线程,而 notify 只能随机唤醒一个等待线程,notifyAll 是唤醒所有等待线程,就不那么【精确】
- park & unpark 可以先 unpark,而 wait & notify 不能先 notify