多线程篇五——wait和notify

news2024/11/22 18:58:05

多线程篇五——wait和notify

如笔者理解有误,欢迎交流指正⭐


线程的执行先后顺序难以预料【抢占式执行】,但是实际开发中我们会需要掌握当下线程的执行顺序.
这就是wait和notify的作用.【都是Object方法即随便定义一个对象豆可以使用wait和notify】

wait()方法
wait执行过程

1.释放当前的锁
2.让线程进入阻塞
3.当线程被唤醒的时候重新获取到锁

上代码

public class Demo15 {
    public static void main(String[] args) throws InterruptedException {
        Object object = new Object();
        synchronized (object) {
            System.out.println("waiting...");
            object.wait();
            System.out.println("end.");
        }
    }
}

运行发现wait一直处于等待状态

1

tips
wait搭配synchronized使用,synchronized加锁给对象头进行标记

wait结束等待的条件

其他线程调用该对象的notify方法
wait等待超时(timeout用来指定等待时间)
其他线程调用该等待线程的interrupted方法,抛出InterruptedException异常

wait和sleep的对比
共同点

让线程在一段时间里不执行.【wait用于线程间通信(生产者-消费者模型) sleep用于线程阻塞(延迟操作)】

不同点

1.wait()可通过notify()唤醒,sleep()通过Interrupt()唤醒
2.使用wait()时没有设置最大等待时间,而sleep()是在知道最大时限的情况下使用(通过异常唤醒,说明程序应该是出现特殊情况了).
3.wait()搭配synchronized使用,sleep()不用.
4.wait()是Object的方法,sleep()是Thread的静态方法.
5.wait()方法会释放锁,sleep()不会.

notify()方法

此时我们的notify()方法就担起了唤醒wait()方法的大任(唤醒等待的线程).
tips
notify()要在同步方法或同步块中调用.它会通知可能等待该对象对象锁的其他线程,使得它们重新获取对象锁.
如果有多个线程等待,有线程调度器随机挑选一个wait状态的线程[【无先来后到】
调用notify()方法后不会立即释放对象锁,要等到执行notify()方法的线程将程序执行完之后【退出同步代码块】才会释放对象锁.

notify唤醒线程过程

1.创建 WaitTask 类, 对应一个线程, run 内部循环调用 wait.
2.创建 NotifyTask 类, 对应另一个线程, 在 run 内部调用一次 notify 注意, WaitTask 和 NotifyTask 内部持有同一个 Object locker.
3.WaitTask 和 NotifyTask 要想配合 就需要搭配同一个 Object.

public class Demo16 {
        public static Object locker = new Object();

        public static void main(String[] args) {
            Thread t1 = new Thread(() -> {
                synchronized (locker) {
                    System.out.println("t1 wait 之前");
                    try {
                        //t1执行到这,就会先立即释放锁,进入wait方法(释放锁+阻塞等待)
                        locker.wait();
                        System.out.println("t1 wait 之后");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });

            Thread t2 = new Thread(() -> {
                try {
                    //t2执行起来之后,先进行sleep(3000)(这个sleep操作就可以让t1先拿到锁)
                    //如果先notify虽然不会有副作用(不会出现异常之类的),但是wait就无法被唤醒,逻辑上有问题
                    Thread.sleep(3000);
                    //t2sleep结束之后,由于t1是wait状态,t2就能拿到锁
                    //接下来打印t2notify之前,执行notify操作,这个操作就能唤醒t1(此时t1就从WAITING状态恢复过来了)
                    synchronized (locker) {
                        System.out.println("t2 notify 之前");
                        locker.notify();
                        //但是由于t2此时还没有释放锁,WAITING恢复之后,尝试获取锁,就可能出现一个小小的阻塞,这个阻塞是由锁竞争引起的
                        //t1目前处于BLOCKED状态,但是时间比较短,肉眼看不见
                        System.out.println("t2 notify 之后");
                    }
                    //t2释放锁之后,就可以继续执行t1
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            t1.start();
            t2.start();
        }
    }
notifyAll()方法

顾名思义哈 notifyAll()可以唤醒所有方法>
注意
唤醒的这些方法在等待(wait)返回时重新获取锁产生锁竞争,但实际这些锁是串行执行的【锁被哪个线程先获取是不确定的】

区别notify()和notifyAll()

1.唤醒一个/都唤醒
2.没有锁竞争/产生锁竞争
对比可发现notify()比notifyAll()好控制 发生错误的概率更低

未完待续❀❀❀

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2128135.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

跟李沐学AI:长短期记忆网络LSTM

输入们、遗忘门和输出门 LSTM引入输入门、忘记门和输出门 输入门计算公式为:。 遗忘门计算公式为:。 输出门计算公式为:。 它们由三个具有sigmoid激活函数的全连接层处理, 以计算输入门、遗忘门和输出门的值。 因此&#xff0c…

为什么不推荐使用Stack

Java已不推荐使用Stack,而是推荐使用更高效的ArrayDeque 为什么不推荐使用 性能低:是因为 Stack 继承自 Vector, 而 Vector 在每个方法中都加了锁。由于需要兼容老的项目,很难在原有的基础上进行优化,因此 Vector 就被…

鸟类目标检测系统源码分享

鸟类目标检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vis…

亲测好用,ChatGPT 3.5/4.0新手使用手册~

都知道ChatGPT很强大,聊聊天、写论文、搞翻译、写代码、写文案、审合同等等,无所不能~ 那么到底怎么使用呢?其实很简单了,国内AI产品发展也很快,很多都很好用了~ 我一直在用,建议收藏下来~ 有最先进、最…

RocketMQ出现The broker does not support consumer to filter message by SQL92

在使用RocketMQ使用SQL过滤消息的时候,出现下面错误 原因是我们的配置文件没有开启SQL过滤功能,我们需要在每个配置文件中添加下面命令 #开启过滤消息时支持SQL92标准 enablePropertyFiltertrue接着我们重启namesrv与broker服务就解决问题 # 1.进入bi…

Robust Image Denoising through Adversarial Frequency Mixup

基于对抗性混频的鲁棒图像去噪 论文链接:https://openaccess.thecvf.com/CVPR2024/Ryou_Robust_Image_Denoising_through_Adversarial_Frequency_Mixup 项目链接:https://github.com/dhryougit/AFM Abstract 基于深度神经网络的图像去噪方法经常与训练…

哈希表的底层实现(1)---C++版

目录 哈希表的基本原理 哈希表的优点 哈希表的缺点 应用场景 闭散列法 开散列法 开放定值法Open Addressing——线性探测的模拟实现 超大重点部分评析 链地址法Separate Chaining——哈希桶的模拟实现 哈希表(Hash Table)是一种数据结构&#x…

STM32G070 CubeMX配置多通道/单通道ADC+DMA流程 LL库

基础配置不再赘述,时钟这些根据硬件来配置 多通道ADCDMA配置图: 程序配置: 调试查看内存数据,硬件上将PA1接到GND,PA2接到3V3 采集的数据会循环覆盖内存 问题:代码里先初始化ADC_IN1,再初…

Spring扩展点系列-ApplicationContextAwareProcessor

文章目录 简介源码分析示例代码示例一:扩展点的执行顺序运行示例一 示例二:获取配置文件值配置文件application.properties内容定义工具类ConfigUtilcontroller测试调用运行示例二 示例三:实现ResourceLoaderAware读取文件ExtendResourceLoad…

CleanClip - 「CleanClip」是一款专为 Mac 设计的桌面剪贴板工具

官方介绍 欢迎使用 CleanClip —— Mac 上最简洁高效的剪贴板管理工具。CleanClip 专为追求简约操作体验的用户设计,它帮助用户记录系统剪贴板上的内容,并提供强大的分类管理能力,帮助你整理复制的内容,提高办公效率。 智能简洁&…

MAVEN如何导入项目

工作中经常需要导入他人的项目,那么如何导入呢? 1, 选择Maven面板,点 2,选中对应项目的pom.xml,双击即可 3,如果没有maven面板,可以选择view->Appearnce->Tool Window Bars…

HTML5元素定位

1.元素定位 为了实现网页整体布局,我们先要知道,一个元素,是如何定位到页面上的某个位置的,这就是元素定位。 元素定位有四种,可以使用position样式来设置元素定位,所以此属性值有四种: stat…

MybatisPlus新增数据时怎么返回新增数据的id

问:MybatisPlus新增数据时怎么返回新增数据的id?答:当插入操作执行后,MyBatis Plus会自动获取生成的ID并将其设置到传入的实体类对象的id属性中。当然,这需要你的表字段ID是自增的 实体类代码 public class Sites {p…

东风德纳携手纷享销客打造汽车零部件行业营销数智化新标杆

为进一步提升数字化经营管理水平,加速数字化转型,推进“品牌向上”战略落实落地,9月2日,东风德纳车桥有限公司召开CRM项目启动会,携手纷享销客,打造汽车零部件行业营销数智化标杆工程。东风德纳车桥总经理陆…

高效Flutter应用开发:GetX状态管理实战技巧

探索GetX状态管理的使用 前言 在之前的文章中,我们详细介绍了 Flutter 应用中的状态管理,setState、Provider库以及Bloc的使用。 本篇我们继续介绍另一个实现状态管理的方式:GetX。 一、GetX状态管理 基础介绍 GetX 是一个在 Flutter 中…

【原创】【总结】【C++类的设计要点】一道十分典型的含继承与虚函数的类设计题

设计类时的要点 1构造函数与析构函数:先在public中写上构造函数与析构函数 2成员函数:根据题目要求在public中声明成员函数;成员函数的实现在类内类外均可,注意若在类外实现时用::符号表明是哪个类的函数 3数据成员:关…

STM32L051K8U6-HAL-串口中断控制灯闪烁速度

HAL三步法: 1、配置下载线 2、配置晶振 3、配置时钟 4、 配置灯引脚属性为输出模式。并设置标签为LED 5、配置串口1 串口常用函数说明: 需要实现的伪代码: 示例:链接:https://pan.baidu.com/s/1u6FamKgZhvcEsFAdgGeaw…

Realsense D455 imu 数据不输出?

现象 realsense_viewer 可以可视化查看imu数据, 但是realsense-ros 查看/camera/accel/sample和/camera/gyro/sample没有数据输出 背景 realsense_viewer 安装: sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-key F6E65AC044F831AC80A06380C8B3A55A6F3EFCDE…

移动通信为啥要用双极化天线?

❝本文简单介绍下移动通信为啥要用双极化天线及其简单概述。 移动通信为啥要用双极化天线? - RFASK射频问问❝本文简单介绍下移动通信为啥要用双极化天线及其简单概述。什么是极化?电磁波的极化通常是用其电场矢量的空间指向来描述:在空间某…

Leetcode 字母异位词分组

这道题目的意思就是:把包含字母字符相同的单词分到同一组。 算法思路: 使用哈希表来解决。 首先将每个字符串进行排序,将排序之后的字符串作为 key,然后将用 key 所对应的异位词组 作为value。然后我们使用 std::pair 来遍历 键…