wait/notify/notifyAll的作用是为了避免轮询带来的性能损失,而产生轮询的条件是多个线程对同一个资源进行操作。即,一般在synchronized 同步代码块里使用 wait()、notify()、notifyAll() 方法;
- obj.wait() 让进入 object 锁的线程到等待状态;
- obj.notify() 在object 上正处于等待状态的线程中挑一个唤醒;
- obj.notifyAll() 让 object 上正处于等待状态的所有线程全部唤醒;
他们都是线程之间进行写作的手段,都属于Object 对象的方法,因此必须要获得此对象的锁,才能调用这几个方法。
@Slf4j
public class WaitNotifyDemo {
static final Object objectLock = new Object();
public static void main(String[] args) {
Thread.currentThread().setName("Main主线程");
synchronized (objectLock) {
try {
objectLock.wait();
log.info("主线程进入等待状态");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
通过运行可以知道 线程在运行后,主线程一直处于等待状态,等待后,下面的代码不在运行。
重点来了:wait 可传参也可以不传参,传参的话,表示只等待多少时间,不传参的话会一直等待,需要其他线程进行唤醒,那两种方式都能唤醒,又如何做区分呢?
这里我们将采用全局变量做标记的方式,还有人建议使用 时间进行记录的方式,但是这种方式不能够很精确的判断。
场景:有三个线程, A线程在做饭(5 s 做好),B和C线程吃饭, B和C先准备碗筷等工作,然后等待A线程做好饭才能吃, 然而 C 线程吃饭比较有脾气,等你 3 s ,还做不好饭菜,他就不吃了,走人了。
代码实现:
@Slf4j
public class WaitNotifyDemo02 {
private static Boolean flag;
final static Object objectFood = new Object();
public static void main(String[] args) throws InterruptedException {
Thread.currentThread().setName("【A线程做饭】");
Thread thread01 = new Thread(() -> {
synchronized (objectFood) {
log.info("B线程准备碗筷中……");
log.info("B线程准备好了碗筷,等待饭菜做好……");
try {
flag = true;
objectFood.wait(3000);
if (flag) {
log.info("B线程等急了,生气走了……");
} else {
log.info("B线程开始了享用美味的饭菜……");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "【B线程吃饭】");
Thread thread02 = new Thread(() -> {
synchronized (objectFood) {
log.info("C线程准备碗筷中……");
log.info("C线程准备好了碗筷,等待饭菜做好……");
try {
objectFood.wait();
log.info("C线程开始了享用美味的饭菜……");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "【C线程吃饭】");
thread01.start();
thread02.start();
log.info("A线程在努力的制作饭菜中………………");
Thread.sleep(5000);
log.info("A线程用时5秒做好了饭菜……");
synchronized (objectFood) {
// objectFood.notify();
// log.info("A线程随机唤醒B或C可以吃饭了……");
objectFood.notifyAll();
flag = false;
log.info("A线程唤醒B和C可以吃饭了……");
}
}
}
运行结果:
14:02:33.186 [【A线程做饭】] INFO 并发编程.WaitNotifyDemo02 - A线程在努力的制作饭菜中………………
14:02:33.186 [【B线程吃饭】] INFO 并发编程.WaitNotifyDemo02 - B线程准备碗筷中……
14:02:33.191 [【B线程吃饭】] INFO 并发编程.WaitNotifyDemo02 - B线程准备好了碗筷,等待饭菜做好……
14:02:33.191 [【C线程吃饭】] INFO 并发编程.WaitNotifyDemo02 - C线程准备碗筷中……
14:02:33.191 [【C线程吃饭】] INFO 并发编程.WaitNotifyDemo02 - C线程准备好了碗筷,等待饭菜做好……
14:02:36.200 [【B线程吃饭】] INFO 并发编程.WaitNotifyDemo02 - B线程等急了,生气走了……
14:02:38.196 [【A线程做饭】] INFO 并发编程.WaitNotifyDemo02 - A线程用时5秒做好了饭菜……
14:02:38.196 [【A线程做饭】] INFO 并发编程.WaitNotifyDemo02 - A线程唤醒B和C可以吃饭了……
14:02:38.197 [【C线程吃饭】] INFO 并发编程.WaitNotifyDemo02 - C线程开始了享用美味的饭菜……