等待与通知
/**
* 模拟人听到口令才能吃饭喝水,
* 没有收到指令前会一直等待
*/
public class Person {
private boolean eat = false;
private boolean drink = false;
public synchronized void waitEat() {
while (!eat) {
try {
wait();
System.out.println(Thread.currentThread().getName() + " Person wait to eat");
} catch (Exception e) {
e.printStackTrace();
}
}
}
public synchronized void waitDrink() {
while (!drink) {
try {
wait();
System.out.println(Thread.currentThread().getName() + " Person wait to drink");
} catch (Exception e) {
e.printStackTrace();
}
}
}
public synchronized void noticeEat() {
eat = true;
notify();
}
public synchronized void noticeAllDrink() {
drink = true;
notifyAll();
}
public static void main(String[] args) {
Person p = new Person();
for (int i = 0; i < 3; i++) {
new Thread(() -> p.waitEat(), "demo" + i).start();
}
for (int i = 0; i < 3; i++) {
new Thread(() -> p.waitDrink(), "demo" + (i + 3)).start();
}
try {
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
/**
* 当调用此方法时,所有的的wait线程都会被唤醒,会打印6条日志
*/
p.noticeAllDrink();
/**
* 当调用此方法时,只有一个wait线程会被唤醒,只会打印一条,信号会丢失
*/
p.noticeEat();
}
}
等待通知的标准
等待方:
1、 获取对象的锁;
2、 循环里判断条件是否满足,不满足调用wait方法,
3、 条件满足执行业务逻辑
通知方
1、 获取对象的锁;
2、 改变条件
3、 通知所有等待在对象的线程
超时等待
假设 等待时间时长为T,当前时间now+T以后超时
long overtime = now + T;
long remain = T;//等待的持续时间
while(result不满足条件 && remain>0){
wait(remain);
remain = overtime – now;//等待剩下的持续时间
}
return result;
对象方法对锁的影响
- yield: 此方法只是让线程让出时间片,持有的锁是不释放的
- sleep: 此方法被调用以后,线程进入睡眠状态,持有的锁是不释放的
- wait: 调用方法之前,必须要持有锁。调用了wait()方法以后,锁就会被释放,当wait方法返回的时候,线程会重新持有锁
- notify: 调用方法之前,必须要持有锁,调用notify()方法本身不会释放锁的
- notifyAll: 同notify,有一点不同在于,notifyAll会发出n个信号(n=等待线程数),而notify只会发出一个信号