• Java中wait和notify详解


    线程的调度是无序的,随机的,但是也是有一定的需求场景,希望能够有序执行,join算是一种控制顺序的方式(功能有限)——》一个线程执行完,才能执行另一个线程!

    本文主要讲解的:wait和notify则有一下功能:

    wait:就是让某个线程先暂停下来,等一等

    notify:就是把该线程唤醒,能够继续执行

    wait:发现条件不满足/时间不成熟,就先阻塞等待

    notify:其他线程构造了一个成熟的条件,就可以唤醒wait的等待

    wait和notify都是Object的方法,只要你是个类对象(不是基本的数据类型)都可以使用wait和notify

    Object.wait主要做的三件事:

    1. 解锁(先加锁,才能解锁)
    2. 阻塞等待
    3. 当收到通知的时候,就会唤醒,同时尝试重新获取锁

    wait必须写到synchronized代码块里面~

    notify也是要放到synchronized中使用的~

    1. public class Main4 {
    2. public static void main(String[] args) throws InterruptedException {
    3. Object object=new Object();
    4. //加锁对象必须和wait的对象是同一个
    5. synchronized (object){
    6. object.wait();
    7. }
    8. }
    9. }

    加锁对象必须和wait的对象是同一个

    对于wait和notify而言:值得注意的是:

    必须要先执行wait,然后notify,此时才有效果~
    如果现在还没有wait,就notify,相当于:一炮打空(没有额外的副作用,但是代码的功能不能正确执行了!),此时wait无法唤醒,代码也不会出现其他异常~!!

    我们来看一下下述代码:

    1. public class Main5 {
    2. public static void main(String[] args) throws InterruptedException{
    3. Object locker=new Object();
    4. Thread t1= new Thread(()->{
    5. while (true){
    6. try {
    7. System.out.println("wait 开始");
    8. synchronized (locker) {
    9. locker.wait();
    10. }
    11. } catch (InterruptedException e) {
    12. e.printStackTrace();
    13. }
    14. }
    15. });
    16. t1.start();
    17. //让t1先启动,主线程休息1秒,在主线程休息1秒的过程中,
    18. // t1线程应该执行到:synchronized (locker) {locker.wait(); }的位置,等1秒钟数据到t2开始执行notify
    19. Thread.sleep(1000);
    20. Thread t2=new Thread(()->{
    21. synchronized (locker){
    22. System.out.println("notify 开始");
    23. locker.notify();
    24. System.out.println("notify 结束");
    25. }
    26. });
    27. t2.start();
    28. }
    29. }

    上述代码的运行结果为:

    解析:t1先执行,执行到了wait就阻塞了,t1之后t2开始执行,执行到了notify就会通知t1线程开始唤醒(注意:notify是在synchronized内部,就需要t2释放了锁,t1才能继续往下走~

    在上述代码中,虽然是t1先执行的,但是可以通过wait,notify控制,让t2先执行一些逻辑,t2执行完之后,notify唤醒t1,t1在继续往下执行~

    使用wait阻塞等待会让线程进入WAITING状态

    wait也提供了一个带参数的版本,参数指定的是最大等待时间!

    不带参数的wait是死等,带参数的wait就会等到最大时间之后,还没人通知,就自己唤醒自己!!

    join只能是让t2线程执行完,再继续执行t1,一定是串行的

    wait和notify可以让t2线程执行完,再让t1执行……,t1执行完一部分,再让t2执行,t2在执行一部分,在让t1执行…………

    对于唤醒操作,还有一个notifyAll(notify用的比较多)

    可以有多个线程,等待同一个对象的情况!!如:在t1,t2,t3中都调用了object.wait,此时在main中,调用了object.notify,会随机唤醒t1,t2中的一个线程,另外两个仍然是WAITING状态!如果调用了object.notifyAll,此时就会把t1,t2,t3的三个线程都唤醒,此时三个线程就会重新竞争锁,然后依次执行……

    wait和sleep的对比(面试题)

    由于wait有一个带参数的版本,用来体现超时时间,这个感觉跟sleep差不多!!

    wait也能提前唤醒,sleep也能提前唤醒,

    wait解决的是线程之间的顺序控制,sleep单纯的是让当前线程休眠一会!

    唯一相同点是:都可以让线程放弃执行一段时间!

    wait需要搭配synchronized使用,sleep不需要

    wait是Object的方法,sleep是Thread的静态方法~

  • 相关阅读:
    ​思想茶叶蛋 (Jul 31,2022)| 元宇宙(Metaverse)下了一枚什么样的蛋
    力扣-2562.找出数组的串联值
    Java方法案例
    Taurus .Net Core 微服务开源框架:Admin 插件【4-3】 - 配置管理-Mvc【Plugin-MicroService 微服务】
    1110 区块反转分数 25
    Java基础
    Pycharm配置Git以及Gitee实现代码管理(全网最详细)
    【linux命令讲解大全】045.网络数据分析利器:深度解读 tcpdump 抓包工具的使用方法
    代码随想录训练营第38天|理论基础 、LeetCode 509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯
    Android stdio 无法新建或打开AIDL文件(解决方法)
  • 原文地址:https://blog.csdn.net/weixin_64308540/article/details/132780361