目录
例如:一个线程修改了一个对象的值,而另一个线程感知到了变化,然后进行相应的操作,整个过程开始于一个线程,而最终执行又是另一个线程,前者是生产者,后者是消费者。
要想做到上面的需求,我们常规思路是:让消费者线程不断地循环检查变量是否符合预期在while循环中设置不满足的条件,如果条件满足则退出while循环,从而完成消费者的工作。
但是却存在如下问题:
1)难以确保及时性
2)难以降低开销,如果降低睡眠的时间,比如休眠1毫秒,这样消费者能更加迅速地发现条件变化,但是却可能消耗更多的处理器资源,造成了无端的浪费。
那用什么呢?——等待/通知机制
一、等待/通知机制
是指一个线程A调用了对象O的wait方法进入等待状态,而另一个线程B调用了对象O的notify或者notifyAll方法,线程A收到通知后从对象O的wait方法返回,进而执行后续操作。上述两个线程通过对象O来完成交互,而对象上的wait和notify/notifyAll的关系就如同开关信号一样。用来完成等待方和通知方之间的交互工作。
二、方法讲解
- notify: 通知一个在对象上等待的线程,使其从wait方法返回,而返回的前提是该线程获取到了对象的锁,没有获得锁的线程重新进入WAITING状态。
- notifyAll:通知所有等待在该对象上的线程
- wait:调用该方法的线程进入WAITING状态,只有等待另外线程的通知或被中断
才会返回 . 需要注意 , 调用 wait() 方法后 , 会释放对象的锁
- wait(long):超时等待一段时间,这里的参数时间是毫秒,也就是等待长达n毫秒,如果没有
通知就超时返回
三、等待和通知的标准范式
三者都必须在同步方法或者同步代码块中调用,否则会抛异常。
1.wait:
syn(对象){
while(条件不满足){
对象.wait()
}
//业务逻辑
}
2.notify/notifyAll:
syn(对象){
//业务逻辑,改变条件
对象.notify/notifyAll();
}
四、notify和notifyAll应该用谁?
notify是通知任意一个线程,我们无法确保被唤醒的这个线程一定就是我们需要唤醒的线程
notifyAll是通知所有线程,它有可能会唤醒我们不想被唤醒的线程
可以看出用哪一个都会有可能出问题。
- 使用
notify()
时要确保只需要唤醒一个线程 - 使用
notifyAll()
时可以避免遗漏,适用于有多个等待线程和复杂条件的场景。