文章目录
- 1.前言
- 2.wait和notify的基本使用
- 3. notifyAll方法
- 4. wait和sleep方法的对比
- 5. 总结
1.前言
在Java多线程环境中,线程之间是抢占式执行的,线程的调度是随机的.这就很难受了. 在很多情况下我们希望线程以我们想要的顺序来执行. 这就需要wait
和notify
这两个方法
2.wait和notify的基本使用
首先是wait
方法
wait是Object
类的方法,而Java中的类都是间接或直接继承于Object类. 因此只要是类的实例都可以调用wait方法
运行上述代码:
可以看到这里抛出了一个 非法的锁状态异常
其实wait
方法的执行分为三步:
- 释放当前锁
- 进行等待通知
- 满足一定的条件(其它线程调用notify),被唤醒,然后重新获取锁
什么要先释放锁,再进行等待通知呢?
因为wait如果不释放锁,可能会影响到其它线程的执行,就是为了保证不影响其它线程的执行
因此wait
与锁密不可分
对上述代码进行加锁,就不会抛出异常了.
但上述代码的执行并没有结束,因为线程在调用wait
方法之后,会一直处于阻塞状态,直到有其它线程调用notify
方法为止.
而调用notify
方法的线程要和调用wait
方法的线程是针对同一个对象进行加锁的才行.
示例:
public static void main(String[] args) {
Object object = new Object();
Thread t1 = new Thread(() ->{
while(true){
synchronized (object){
System.out.println("wait 之前");
try {
object.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("wait 之后");
}
}
});
t1.start();
Thread t2 = new Thread(() ->{
while(true){
synchronized (object){
System.out.println("notify 之前");
object.notify();
System.out.println("notify 之后");
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
t2.start();
}
运行截图:
上述标注的是一组 wait
和notify
方法的执行流程.
注: 如果先调用的是notify
方法,代码并不会有什么影响.
3. notifyAll方法
Java中除了使用notify
方法唤醒线程,还有一个notifyAll
方法.
当一个线程调用了某个对象的notifyAll方法后,该对象上的所有等待线程将被唤醒,即使唤醒了所有在等待的线程,这些线程之间也要进行锁竞争(串行执行)。
4. wait和sleep方法的对比
wait
方法和sleep
方法的对比也是面试中经常会问到的问题
对于这个问题,可以从相同点和不同点进行回答:
相同点: 都是让线程进入阻塞等待状态
不同点:sleep方法是通过时间来通知唤醒,而wait方法则需要使用notify或notifyAll进行唤醒
5. 总结
wait
和notify
方法用于实现线程间的协作和通信.
wait方法使线程进入等待状态,notify方法唤醒一个等待线程,notifyAll方法唤醒所有等待线程。
通过上述三个方法,可以使线程按照特定的顺序执行或者等待某个条件满足后再执行。
感谢你的观看!希望这篇文章能帮到你!
专栏: 《从零开始的Java学习之旅》在不断更新中,欢迎订阅!
“愿与君共勉,携手共进!”