文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

wait 和 notify

2023-09-21 20:21

关注

请添加图片描述

✨个人主页:bit me👇
✨当前专栏:Java EE初阶👇
✨每日一语:阅己,越己,悦己;自行,自省,自醒;无味,无谓,无畏。

目 录

⏰一. wait 和 notify 的引入

由于线程之间是抢占式执行的, 因此线程之间执行的先后顺序难以预知. 但是实际开发中有时候我们希望合理的协调多个线程之间的执行先后顺序.

wait 和 notify 相比于 join 能更好的控制线程之间的执行顺序

注意: wait, notify都是 Object 类的方法.

  • 使用 o1.notify() 就可以唤醒调用 o1.wait 的线程!!
  • 使用 o2.notify() 是不可以唤醒调用 o1.wait 的线程!

 

⏲二. wait()方法和notify()方法

对于 wait 来说,内部的执行过程还有点小麻烦

  1. 释放锁

wait 一上来就得释放锁,,得在调用 wait 之前,先拿到锁,wait 必须要放到 synchronized 中使用,synchronized 加锁的对象必须是和调用 wait 方法的对象是同一个对象,还得和调用 notify 的对象是同一个对象!!!

  1. 等待通知

  2. 当通知到达之后,就会被唤醒,并且尝试重新获取锁

wait 结束等待的条件:

代码示例: 观察wait()方法使用

public class Demo17 {    public static void main(String[] args) throws InterruptedException {        Object object = new Object();        synchronized (object) {            System.out.println("wait 之前");            object.wait();            System.out.println("wait 之后");        }    }}

在这里插入图片描述

notify 方法是唤醒等待的线程

举例实现 wait 和 notify 的内部执行过程:创建两个线程 一个线程调用 wait,一个线程调用 notify

public class Demo18 {//这个对象用来做锁对象public static Object locker = new Object();public static void main(String[] args) {    //用来取等待    Thread waitTask = new Thread(()->{        synchronized (locker) {            try {                System.out.println("wait 开始");                locker.wait();                System.out.println("wait 结束");            } catch (InterruptedException e) {                e.printStackTrace();            }        }    });    waitTask.start();    //创建一个用来通知 / 唤醒的线程    Thread notifyTask = new Thread(()->{       //让用户来控制,用户输入某个内容之后,再执行通知        Scanner scanner = new Scanner(System.in);        System.out.println("输入任意内容,开始通知:");        //next 会阻塞,直到用户真正输入内容以后        scanner.next();        synchronized (locker){            System.out.println("notify 开始");            locker.notify();            System.out.println("notify 结束");        }    });    notifyTask.start();}}

执行过程及结果:

在这里插入图片描述

线程 1 需要先计算一个结果,线程 2 来使用这个结果,线程 2 就可以 wait ,线程 1 计算完结果之后,notify ,唤醒线程 2。

例如:

多个线程抢占一个锁,一个线程 A 抢到了,其他线程排队等待,但是抢到锁的线程 A 却无法完成任务,占着锁不放,导致其他锁也不能干活儿,于是这个线程 A 决定释放锁出来,在外面等待,给其他的锁一些机会,由于线程之间在系统里的调度是随机的,可能下次又是线程 A 进来了,于是多次情况下都是线程 A 占用了 CPU,其他线程都碰不到,导致线程饿死,旱的旱死,涝的涝死。

因此使用 wait 和 notify 就可以解决上述问题,让后面的多个线程拿到锁之后判定当前任务是否可以执行,如果能就干活,不能就进行 wait !wait 来等待合适的时候(条件满足)再继续执行 / 再参与竞争锁

拓展:

这三个阻塞的状态,都会导致 PCB 进入内核队列中对应的阻塞队列。操作系统内核是不区分这三个的状态的!这三个状态是 JVM 中的状态,操作系统内核中衡量线程的状态是另外的方式,没有 JVM 里面的这么细。

notify方法只是一次唤醒某一个等待线程. 使用notifyAll方法可以一次唤醒所有的等待线程.

 

⏱三. wait 和 sleep 的对比(面试题)

其实理论上 wait 和 sleep 完全是没有可比性的,因为一个是用于线程之间的通信的,一个是让线程阻塞一段时间,唯一的相同点就是都可以让线程放弃执行一段时间

他们俩都会让线程进入阻塞,阻塞的原因和目的不同,进入的状态也不同,被唤醒的条件也不一样。

实际开发中会很少使用 sleep ,目的是为了 “放权” ,暂时让出当前 CPU 的使用权。之所以 sleep 使用的少,等待的时间太固定了,要是有突发情况想提前唤醒并不是那么容易,wait 就用的比较多了,wait 可以进行死等,也能设置最长等待时间(涵盖了 sleep 的功能)

1. wait 需要搭配 synchronized 使用. sleep 不需要.
2. wait 是 Object 的方法 sleep 是 Thread 的静态方法.

来源地址:https://blog.csdn.net/m0_67660672/article/details/129505822

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯