JUC并发编程 -- 为什么需要wait/notify方法 & 原理之 wait / notify & wait() 和 notify() API介绍
Posted Z && Y
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JUC并发编程 -- 为什么需要wait/notify方法 & 原理之 wait / notify & wait() 和 notify() API介绍相关的知识,希望对你有一定的参考价值。
1. 为什么需要wait/notify方法
- 由于条件不满足,小南不能继续进行计算
- 但小南如果一直占用着锁,其它人就得一直阻塞,效率太低
- 于是老王单开了一间休息室(调用 wait 方法),让小南到休息室(WaitSet)等着去了,但这时锁释放开,其它人可以由老王随机安排进屋
- 直到小M将烟送来,大叫一声 [ 你的烟到了 ] (调用 notify 方法)
- 小南于是可以离开休息室,重新进入竞争锁的队列
2. 原理之 wait / notify
- Owner 线程发现条件不满足,调用 wait 方法,即可进入 WaitSet 变为 WAITING / TIMED_WAITING 状态(已经获得了锁,但是条件不满足又释放了锁)
- BLOCKED(没有获得锁 正在等待获取锁) 和 WAITING / TIMED_WAITING 的线程都处于阻塞状态,不占用 CPU 时间片,BLOCKED 线程会在 Owner 线程释放锁时唤醒
- WAITING / TIMED_WAITING 线程会在 Owner 线程调用 notify 或 notifyAll 时唤醒,但唤醒后并不意味者立刻获得锁,仍需进入EntryList 重新竞争
3. notify & wait() 和 notify() API介绍
1.1 API介绍
它们都是线程之间进行协作的手段,都属于 Object 对象的方法。必须获得此对象的锁,才能调用这几个方法
- obj.wait() 让进入 object 监视器的线程到 waitSet 等待
- obj.notify() 在 object 上正在 waitSet 等待的线程中挑一个唤醒
- obj.notifyAll() 让 object 上正在 waitSet 等待的线程全部唤醒
1.2 示例代码:
notify(): 唤醒随机一个等待状态的线程
package tian;
import lombok.extern.slf4j.Slf4j;
@Slf4j(topic = "c.TestWaitNotify")
public class TestWaitNotify {
final static Object obj = new Object();
public static void main(String[] args) throws InterruptedException {
new Thread(() -> {
synchronized (obj) {
log.debug("执行....");
try {
obj.wait(); // 让线程在obj上一直等待下去
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("t1线程的其它代码....");
}
}, "t1").start();
new Thread(() -> {
synchronized (obj) {
log.debug("执行....");
try {
obj.wait(); // 让线程在obj上一直等待下去
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("t2线程的其它代码....");
}
}, "t2").start();
// 主线程两秒后执行
Thread.sleep(2000);
log.debug("唤醒 obj 上其它线程");
synchronized (obj) {
obj.notify(); // 唤醒obj上随机一个等待状态的线程
// obj.notifyAll(); // 唤醒obj上所有等待线程
}
}
}
运行结果:
这里唤醒了t1线程
notifyAll(): 唤醒所有等待线程
上诉代码改进:
运行结果:
1.3 带参数的wait()方法
-
wait() 方法会释放对象的锁,进入 WaitSet 等待区,从而让其他线程就机会获取对象的锁。无限制等待,直到notify 为止
-
wait(long n) 有时限的等待, 到 n 毫秒后结束等待继续运行线程后面的代码,或是被 notify 后运行线程后面的代码。
-
wait(long timeout, int nanos) 这个方法里面有2个参数第一个参数是毫秒,第二个参数是纳秒,但这个纳秒是个假的纳秒,所以用的很少,一般用带一个参数的wait方法就足够了。
以上是关于JUC并发编程 -- 为什么需要wait/notify方法 & 原理之 wait / notify & wait() 和 notify() API介绍的主要内容,如果未能解决你的问题,请参考以下文章
JUC并发编程 -- 为什么需要wait/notify方法 & 原理之 wait / notify & wait() 和 notify() API介绍