目录
线程之间是 抢占式执行的,调度是无序的,再实际开发中,要求协调多个线程之间的执行先后顺序;
- wait():让当前对象进入等待状态
- notify()/notifyAll():唤醒在当前对象上的等待的线程
wait()、notify()、notifyAll()都是 Object类方法
1、wait() 方法
wait() 方法是Object类的方法,用于将当前线程置于等待状态,并且会释放当前线程所持有的锁;
主要做的事情:
- 解锁:释放当前的锁(前提拥有锁)
- 阻塞等待:当前线程进入等待状态
- 满足条件或收到通知,就唤醒,重新尝试获取锁
结束条件:
- notify唤醒:其他线程调用该对象的notify方法;
- wait()等待超时:wait()可以指定等待时间,超时就自动唤醒
- 其他线程调用该线程的 interrupted方法,导致wait抛异常;
2、notify() 方法
用于唤醒 一个正在等待的该对象锁的线程,如果有多个线程在等待该对象锁,则只会唤醒其中一个线程,具体是哪一个由JVM调度决定;
使用:
- 必须在同步块中调用,并且必须拥有该对象的锁(与wait()的对象是同一个);
- 也是在 synchronized 中使用,必须先执行 wait,在执行 notify 才有效果,没先执行wait,notify 执行无效果;
- 执行notify方法后,当前线程不会立即释放该对象锁,等调用notify方法的线程执行完毕,才会释放锁
notifyAll()方法
与notify()唤醒一个线程不同,notifyAll()是唤醒所有等待该对象锁的线程,同步竞争;
3、小结
wait()和notify()方法虽然可以实现线程之间的协作,但使用不当可能会导致线程死锁或者线程饥饿的问题。
特点 | wait() | notify() |
执行条件 | 必须在 synchronized 代码块中 | 必须在 synchronized 代码块中 |
对象锁 | 调用前必须先获得对象锁 | 调用前必须先获得对象锁 |
释放锁 | 是 | 否 |
执行 | 执行后进入 等待状态,等待唤醒 唤醒后,进入竞争锁,继续执行 | 必须在wait执行后,调用才有效果,没有先执行wait,等于打空 |
中断 | 抛出InterruptedException异常 | 不会出现异常 |
线程状态 | 进入等待状态 | 从等待返回运行状态 |
代码演示:
public static void main(String[] args) throws InterruptedException {
Object locker = new Object();
//
Thread thread1 = new Thread(()->{
System.out.println("wait 开始");
//必须在 synchronized 中执行
synchronized (locker){
try {
locker.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("wait 结束");
});
thread1.start();
Thread.sleep(1000);
Thread thread2 = new Thread(()->{
System.out.println("notify 开始");
//必须在 synchronized 中执行
synchronized (locker){
locker.notify();
}
System.out.println("notify 结束");
});
thread2.start();
}