提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
上一章https://blog.csdn.net/m0_45364328/article/details/124925295
我们介绍了synchronized的原理,并提出了Monitor的概念,这一章我们介绍一下wait/notify的原理,加深对Monitor的理解
小故事
wait/notify的原理
- Owner线程发现条件不满足,调用wait方法,即可进入WaitSet变为WAITING
- BLOCKED和WAITING的线程都处于阻塞状态,不占用CPU时间片
- BLOCKED线程会在Owner线程释放锁时唤醒
- WATING线程会在Owner线程调用notify和notifyAll时唤醒,但唤醒后并不意味着立刻获得锁,仍需进入EntryList重新竞争
API介绍
- obj.wait()让进入object监视器的线程到waitSet等待
- obj.notify()在object上正在waitSet等待的线程中挑一个唤醒
- obj.notifyAll()让object上正在waitSet等待的线程全部唤醒
它们都是线程之间进行协作的手段,都属于Object对象的方法。必须先获得此对象的锁,才能调用这几个方法
final static Object obj = new Object();
public static void main(String[] args) {
new Thread(() -> {
synchronized (obj) {
log.debug("执行....");
try {
obj.wait(); // 让线程在obj上一直等待下去
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("其它代码....");
}
}).start();
new Thread(() -> {
synchronized (obj) {
log.debug("执行....");
try {
obj.wait(); // 让线程在obj上一直等待下去
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("其它代码....");
}
}).start();
// 主线程两秒后执行
sleep(2);
log.debug("唤醒 obj 上其它线程");
synchronized (obj) {
obj.notify(); // 唤醒obj上一个线程
// obj.notifyAll(); // 唤醒obj上所有等待线程
}
}
Wait()方法会释放对象的锁,进入WaitSet等待区,从而让其他线程有机会获得对象的锁。无限制等待,直到notify为止。Wait(long n) 有限时的等待,到毫秒后结束等待,或被notify
Sleep(long n)和wait(long n)的区别:
1、sleep是Thread方法,而wait是Object方法
2、Sleep不需要强制和synchronized配合使用,但wait需要和synchronized一起使用
3、Sleep在睡眠的同时,不会释放对象锁,但是wait在等待的时候会释放对象锁
Wait notify的正确使用姿势
synchronized (lock){
while (条件不成立){
lock.wait();
}
//干活
}
synchronized (lock){
lock.notifyAll();
}