三、等待与通知
wait()/notify()/notifyAll() 这三个方法都是object 类提供的 其中
wait():
调用该方法的线程进入WAITING 状态,同时释放所持有的对象锁,只有等待通知或者中断才会唤起。
notify():
随机通知一个等待在该对象的线程,使其从wait 方法上唤起,唤起的前提是该线程获取了该对象上的锁,如果没有获取到锁则重新进入WAITING状态
notifyAll():
通知所有等待在该对象上的线程。
其实我们在使用等待与通知是有标准模板的,基本遵循几个原则
注:这边是从某个博客看到,时间久远做了笔记忘记是谁原创的,原作者看到麻烦通知下。。。
等待方:
- 获取对象的锁;
- 循环里判断条件是否满足,不满足调用wait方法,被通知后仍要检查条件
- 条件满足执行业务逻辑
synchronized(对象){
while(条件不满足){
对象.wait();
}
业务代码
}
通知方:
- 获取对象的锁;
- 改变条件
- 通知所有等待在对象的线程
synchronized(对象){
改变条件;
对象.notifyAll();
}
在调用 wait()、notify()系列方法之前,线程必须要获得该对象的对象级别锁,即只能在同步方法或同步块中调用 wait()方法、notify()系列方法。
那么notify()和notifyAll() 我们该怎么选择呢?
在实际开发中我们尽可能使用notifyAll() 而不是notify(),原因就是notify()只会唤醒一个线程,而我们无法确保被唤醒的线程我们需要的,从而增加程序的不确定性。
下面我们使用基本范式演示代码:
/**
* 等待与通知演示代码
* wait()/notify()/notifyAll()
*
* @author ckj
*
*/
public class WaitAntNotifyThread {
private static WaitAntNotifyThread waitAntNotifyThread = new WaitAntNotifyThread(10);
private int distance; // 距离
public WaitAntNotifyThread(int distance) {
super();
this.distance = distance;
}
/* 线程等待距离发现变化 */
public synchronized void waitSnack() throws InterruptedException {
String threadName =Thread.currentThread().getName();
System.out.println("客户"+threadName+"点了一份快递");
while (distance > 0) {
wait();
System.out.println("改变了距离 thread["
+Thread.currentThread().getName()
+"] 是快递员 notified");
}
System.out.println("目前 距离是 "+this.distance);
}
/* 变化距离 并通知等待线程 */
public synchronized void notifyShopper() {
this.distance = 0;
System.out.println("快递员送餐已到达,通知客户");
notify();
}
/* 变化距离 并通知等待线程 */
public synchronized void notifyAllShopper() {
this.distance = 0;
System.out.println("快递员送餐已到达,通知客户");
notifyAll();
}
static class ChangeWait extends Thread{
@Override
public void run() {
try {
waitAntNotifyThread.waitSnack();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
// 唤起三个线程
for(int i=0;i<3;i++) {
new ChangeWait().start();
}
Thread.sleep(1000);
waitAntNotifyThread.notifyShopper(); // 随机唤起
//waitAntNotifyThread.notifyAllShopper(); // 全部唤起
}
}