先看定义
- notify 通知一个在对象上等待的线程,使其从wait()方法返回,而返回的前提是该线程获取到了对象的锁
- notifyAll 通知所有在该对象上的线程
- wait 调用该方法线程进入WAITING的状态,只有等待另外线程的通知或被中断才会返回,需要注意,调用wait()后,会释放对象的锁
看一段示例代码
场景是这样的wait同学跟notify同学一起去面试,他俩在一个同步队列里面,wait先到的先进行了面试,结果就面了30min,面试官让他在旁边的办公室等通知;hr请他到隔壁房间去,让notify同学进来了,跟面试官相见恨晚,聊了足足1.5h,hr已经发出了通知马上出结果,然而notify同学似乎还不满足,撩起了hr小姐姐...
public class WaitNotify {
/**
* flag表示是否通过面试 默认值认为人人皆可通过
*/
static boolean flag = true;
/**
* hrLock表示hr
*/
static Object hrLock = new Object();
public static void main(String[] args) throws Exception {
Thread waitThread = new Thread(new Wait(), "WaitThread");
waitThread.start();
// 模拟间隔2分钟,notify面试同学进场
// TODO TimeUnit.SECONDS.sleep(60*2);
Thread notifyThread = new Thread(new Notify(), "NotifyThread");
notifyThread.start();
}
static class Wait implements Runnable {
@Override
public void run() {
// 加锁,拥有hrLock的Monitor - hr带着wait同学去见面试官
synchronized (hrLock) {
// wait同学进行面试
while (flag) {
try {
// TODO 面试进行了30min
System.out.println(Thread.currentThread().getName() + "同学你在旁边办公室等通知 hrLock.wait -> " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
// 释放锁 - hr开始清场,让wait同学到旁边去
hrLock.wait();
} catch (InterruptedException e) {
}
}
// 面试不通过
System.out.println(Thread.currentThread().getName() + "面试不通过 -> " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
}
}
}
static class Notify implements Runnable {
@Override
public void run() {
// 加锁,拥有hrLock的Monitor - hr带着notify同学去见面试官
synchronized (hrLock) {
// TODO notify跟面试官聊得很愉快,聊了1.5h
// 获取lock的锁,然后进行通知,通知时不会释放lock的锁,
// 直到当前线程释放了lock后,WaitThread才能从wait方法中返回
System.out.println(Thread.currentThread().getName() + "同学,你技术面通过了 hrLock.notifyAll -> " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
// hr通知所有处于等通知状态的同学、我马上过来给你们结果(PS:hr心里早已打算让wait同学gg)
hrLock.notifyAll();
flag = false;
// TODO 模拟间隔5分钟
}
// 再次加锁 - notify同学差不多通过了,拉起hr小姐姐聊起了人生
synchronized (hrLock) {
System.out.println(Thread.currentThread().getName() + "同学你面试通过了,咱俩后面有空再唠(emmmmm.) -> " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
}
}
}
}
复制代码
结果如下
WaitThread同学你在旁边办公室等通知 hrLock.wait -> 18:37:14
NotifyThread同学,你技术面通过了 hrLock.notifyAll -> 18:37:14
NotifyThread同学你面试通过了,咱俩后面有空再唠(emmmmm.) -> 18:37:14
WaitThread面试不通过 -> 18:37:14
复制代码
来张彩图了解一下流程
解释如下- 1.WaitThread首先获取了对象的锁,然后调用对象的wait()方法,从而放弃了锁并进入了对象的等待队列WaitQueue中,进入等待状态。
- 2.由于WaitThread释放了对象的锁,NotifyThread随后获取了对象的锁,并调用对象的notify()方法,将WaitThread从WaitQueue移到SynchronizedQueue中,此时WaitThread的状态变为阻塞状态。
- 3.NotifyThread释放了锁之后,WaitThread再次获取到锁并从wait()方法返回继续执行。
等待/通知的经典范式
等待方规则
- 1)获取对象的锁
- 2)如果条件不满足,那么调用对象的wait()方法,被通知后仍要检查条件
- 3)条件满足则执行对应的逻辑 伪代码
synchronized(对象) {
while(条件不满足) {
对象.wait();
}
对应的处理逻辑
}
复制代码
通知方规则
-
1)获得对象的锁。
-
2)改变条件。
-
3)通知所有等待在对象上的线程。 伪代码
synchronized(对象) {
改变条件
对象.notifyAll();
}
复制代码
参考资料《Java并发编程的艺术》