由于线程之间是抢占式执行的,因此线程之间执行的先后顺序难以预知.
但是实际开发中有时候我们希望合理的协调多个线程之间的执行先后顺序
wait 方法做的事
代码示例:
public class ThreadDemo19 {
public static void main(String[] args) throws InterruptedException {
Object object = new Object();
System.out.println("等待前");
object.wait();
System.out.println("等待后");
}
}
预计执行结果:
此代码中,由于没有进行任何的通知机制;所以,预期效果,是一直去等待
实际执行结果:
synchronized — 监视器锁
wait 要搭配 synchronized 来使用,脱离 synchronized 使用 wait 会直接抛出异常
wait 的工作过程:
1.释放锁 (得先有一个锁,才能释放)
2.等待通知 (这个过程可能很久)
3.当收到通知后,尝试重新获取锁,继续往下执行
修改之后的代码:
public static void main(String[] args) throws InterruptedException {
Object object = new Object();
synchronized (object){
System.out.println("等待前");
object.wait();
System.out.println("等待后");
}
}
此时运行程序,就会陷入阻塞,会持续多久,不好说
可以通过 jconsole 窗口来查看:
wait 方法,的执行过程分为三步,下面线程1 调用wait 方法
画图表示:
如何避免 竞态条件问题??
事实上,操作1 和 操作2 在wait 上是原子的
也就是说,只要调用 wait,1 和 2 是一气呵成的,不会先后执行~
wait 结束等待的条件
notify 方法是唤醒等待的线程
代码示例:
public class ThreadDemo20 {
public static void main(String[] args) throws InterruptedException {
Object locker = new Object();
Thread t1 = new Thread(){
@Override
public void run(){
synchronized (locker){
while (true){
try {
System.out.println("wait 开始");
locker.wait(); // 要和 synchronized 对应的对象对应
System.out.println("wait 结束");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
};
t1.start();
Thread t2 = new Thread(){
@Override
public void run(){
Scanner scan = new Scanner(System.in);
System.out.println("输入任意一个整数, 继续执行notify() ");
int num = scan.nextInt();
synchronized (locker){
System.out.println("notify 开始");
locker.notify(); // notify 的对象和 wait 的对象要对应,才有效果
System.out.println("notify 结束");
}
}
};
t2.start();
}
}
执行结果:
画图分析执行过程:
notify 方法只是唤醒某一个等待线程,使用 notifyAll 方法可以一次唤醒所有的等待线程,这些线程再去竞争同一把锁
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/m0_47988201/article/details/121539544
内容来源于网络,如有侵权,请联系作者删除!