当前位置: 首页 > news >正文

[JavaEE系列] wait(等待) 和 notify(唤醒)

文章目录

  • 目标
  • 为什么需要 wait 和 notify ?
  • 详解 wait 和 notify
    • wait (等待)
    • notify (唤醒)
    • 一段代码了解 wait 和 notify 之间的运行过程
  • 总结
    • wait 和 sleep 的区别(重要)

目标

        本文最终目的是要熟练掌握 wait 和 notify 方法的各种使用场景, 最后再对 wait 和 sleep 进行比较区分.

为什么需要 wait 和 notify ?

        在此之前, 我们控制线程之间的执行顺序的时候, 一是使用 sleep 让某一个线程进入休眠状态, 其他线程可以在此期间执行; 二是使用 synchronized 对线程中的某个部分加锁, 这时候其他线程再访问这个锁的时候就会发生阻塞等待.
        但是使用这两种方法来对线程的执行顺序进行控制是比较麻烦的, 有时候也会出现不准确的情况. 对此, 我们有了一种更为合理的方法来让线程达到能够按照我们指定安排的顺序执行的效果. 那就是使用 wait 方法来让线程进行等待, 以及使用 notify 方法来对线程进行唤醒.

详解 wait 和 notify

wait (等待)

        使用 wait 方法的前提是需要获取到锁(也就是说, wait 必然存在于 synchronized 中, 并且调用 wait 的对象和 synchronized 里使用的锁对象是一个对象的), 因为 wait 方法的功能是: 1. 释放原有的锁; 2. 等待通知(唤醒); 3. 当通知到达后, 尝试重新获取到锁(这就涉及到下面 notify 的东西了).

notify (唤醒)

        使用 notify 方法则是起到了通知 / 唤醒的效果. 当然, 这里调用 notify 方法的对象需要和调用 wait 方法的对象是一样的(也就是和前面 synchronized 里使用的锁对象是一样的). 其次, notify 还有一个重要的特点: 就是在使用 notify 的时候, 不一定需要有 wait, 换句话说, 无论在什么时候使用 notify, 都是无副作用的.

一段代码了解 wait 和 notify 之间的运行过程

public class Main {
    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("输入任意内容执行唤醒:");
            scanner.next();  //此处next会发生阻塞,直到输入内容
            synchronized (locker){
                System.out.println("notify开始");
                locker.notify();
                System.out.println("notify结束");
            }
        });
        notifyTask.start();
    }
}

运行结果:
在这里插入图片描述

        过程: 当 waitTask 线程执行到 wait 的时候, 会先释放 locker 锁, 然后进入阻塞等待, 当再执行接下来的 notifyTask 线程的时候, 执行到 notify 的时候, 就会唤醒之前的 wait, 将PCB由阻塞队列加入到就绪队列中来, 接着继续往下执行这个线程(这里面涉及到的锁对象都是 locker).

        注意: wait 和 notify 机制还能非常有效地避免"线程饿死"的现象, 那么什么是"线程饿死"呢? "线程饿死"就是在某些情况下(具体就是操作系统对线程进行随机调度的原因), 有些线程反复占用CPU, 而有些线程则是始终都进不了CPU执行(正所谓旱的旱死, 涝的涝死), 简单来说就是调度器可能会出现线程分配不均匀的情况.

总结

wait 和 sleep 的区别(重要)

  • 共同点: 它们都是使线程暂停一段时间的方法, 其中, 它们都可以进行死等, 也可以指定最长等待时间.

  • 不同点:

    • wait是Object类中的一个方法, sleep是Thread类中的一个方法
    • wait必须在synchronized修饰的代码块或方法中使用, sleep方法可以在任何位置使用
    • wait被调用后当前线程进入BLOCK状态并释放锁, 并可以通过notify和notifyAll方法进行唤醒; 而sleep被调用后当前线程进入TIMED_WAIT状态, 不涉及锁相关的操作

相关文章:

  • 记我的一次UI还原过程
  • java计算机毕业设计基于安卓Android的健康管理APP
  • 记一次uni-app Android原生插件开发
  • 从汇编深刻理解前置++与后置++
  • 前端笔试题记录(一)
  • 深度学习——(8)回归问题
  • java毕业设计蜗牛兼职网mybatis+源码+调试部署+系统+数据库+lw
  • 2022年8月31日:面向初学者的 web 开发--使用 JavaScript 中的函数创建模块化代码(没看懂)
  • 【玩转Editplus】一个文本编辑器editplus运行Java、js、html、css
  • 【云原生 | Docker】部署 Django Nginx Gunicorn
  • 【STM32】FSMC——扩展外部SRAM
  • 猿创征文|【数据结构】二叉树相关接口的实现及对应OJ题
  • 【操作系统笔记 】进程(1):前驱图和程序执行
  • LeetCode 306周赛 (补记)
  • vue集成海康h5player实现播放
  • [笔记] php常见简单功能及函数
  • 2017届校招提前批面试回顾
  • Babel配置的不完全指南
  • chrome扩展demo1-小时钟
  • Docker 笔记(1):介绍、镜像、容器及其基本操作
  • es的写入过程
  • Fabric架构演变之路
  • fetch 从初识到应用
  • JWT究竟是什么呢?
  • Laravel Mix运行时关于es2015报错解决方案
  • leetcode-27. Remove Element
  • Linux中的硬链接与软链接
  • nfs客户端进程变D,延伸linux的lock
  • nodejs实现webservice问题总结
  • PAT A1092
  • python_bomb----数据类型总结
  • Python连接Oracle
  • React Native移动开发实战-3-实现页面间的数据传递
  • 阿里云爬虫风险管理产品商业化,为云端流量保驾护航
  • 程序员最讨厌的9句话,你可有补充?
  • 前嗅ForeSpider采集配置界面介绍
  • 深入 Nginx 之配置篇
  • 视频flv转mp4最快的几种方法(就是不用格式工厂)
  • 通过获取异步加载JS文件进度实现一个canvas环形loading图
  • 为视图添加丝滑的水波纹
  • 问:在指定的JSON数据中(最外层是数组)根据指定条件拿到匹配到的结果
  •  一套莫尔斯电报听写、翻译系统
  • 怎样选择前端框架
  • 智能合约开发环境搭建及Hello World合约
  • ​LeetCode解法汇总2583. 二叉树中的第 K 大层和
  • ​低代码平台的核心价值与优势
  • (6)【Python/机器学习/深度学习】Machine-Learning模型与算法应用—使用Adaboost建模及工作环境下的数据分析整理
  • (AtCoder Beginner Contest 340) -- F - S = 1 -- 题解
  • (SpringBoot)第二章:Spring创建和使用
  • (编程语言界的丐帮 C#).NET MD5 HASH 哈希 加密 与JAVA 互通
  • (附源码)php新闻发布平台 毕业设计 141646
  • (免费领源码)python#django#mysql公交线路查询系统85021- 计算机毕业设计项目选题推荐
  • (排序详解之 堆排序)
  • (转)ObjectiveC 深浅拷贝学习
  • (转)拼包函数及网络封包的异常处理(含代码)