目录
一、前言
由于线程之间是抢占式执行的,我们不能确定线程的调度顺序,而有时候我们又希望多个线程之间可以有序地协调调度,于是就有了wait()和notify()方法。
wait()和notify()方法都是Object类中的方法,所以我们可以通过任意的对象来调用这些方法。
二、wait()方法
1、wait()方法要做的事
wait()方法表面上看起来只是让线程进入了等待的状态,实际上它要做三件事情:
(1) 释放当前的锁(所以调用wait()方法之前需要先加锁,即配合synchronized关键字使用);
(2) 使当前执行代码的线程进行等待;
(3) 满足一定条件时被唤醒(其他线程中调用了该对象的notify()方法),尝试重新获取锁。
注意:调用wait()方法的对象必须和synchronized的锁对象是同一个对象。
2、结束等待的方式
(1) 其他线程中调用了该对象的notify()方法;
(2) 如果调用的是带参数的wait()方法(可以传入参数来指定等待的时间),等待时间结束即可;
(3) 其他线程中调用该等待线程的interrupted()方法,提前唤醒该等待线程,同时也会抛出InterruptedException异常。
public class Test3 {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
synchronized (Test3.class) {
try {
//t1线程进入wait状态
//锁对象和调用wait方法的对象必须是同一个
Test3.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("t1线程结束");
});
t1.start();
//t1线程启动后休眠1秒
Thread.sleep(1000);
Thread t2 = new Thread(() -> {
t1.isInterrupted();
System.out.println("t2线程中设置标志位");
t1.interrupt();
});
t2.start();
}
}
注意:调用wait()方法和notify()方法的对象必须是同一个,否则无法唤醒线程。
三、notify()方法
notify()方法是用来唤醒调用wait()方法后进入等待的线程,但是调用两个方法的对象必须是同一个对象,如果在线程1中通过A对象调用wait(),而在线程2中通过B对象调用notify(),则无法唤醒A对象所在的线程。
注意:
(1) 如果多个线程中都通过对象A都调用了wait(),那么另外一个线程中通过对象A调用notify(),只会随机唤醒其中一个线程;要想唤醒所有线程,需要调用notifyAll()方法。
(2) 如果线程2先调用notify(),线程1再调用wait(),则线程1会一直等待,无法被唤醒。
代码示例:在t2线程中调用notify()唤醒调用了wait()的t1线程
public class Test4 {
public static void main(String[] args) throws InterruptedException {
Object object = new Object();
Thread t1 = new Thread(() -> {
synchronized (object){
System.out.println("调用wait之前");
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("调用wait之后");
}
});
t1.start();
//t1线程启动后休眠100毫秒,保证先执行t1再执行t2
Thread.sleep(100);
Thread t2 = new Thread(() -> {
synchronized (object){
System.out.println("调用notify之前");
object.notify();
System.out.println("调用notify之后");
}
});
t2.start();
}
}代码运行结果:

四、wait()和sleep()的对比
相同点:都可以让线程放弃执行一段时间。
不同点:
(1)wait()是用于线程间通信的,sleep()是让线程阻塞一段时间;
(2)wait()需要搭配synchronized使用,sleep()不需要;
(3)wait()是Object类的成员方法,sleep()是Thread类的静态方法。