Java 多线程系列Ⅲ(wait+notify+notifyAll)

wait、notify、notifyAll

  • 一、初识 wait、notify、notifyAll
  • 二、wait、notify、notifyAll 功能介绍
    • 1、wait()
    • 2、notify()
    • 3、notifyAll()
    • 4、wait、notify、notifyAll 要点总结
    • 5、wait/notify 使用示例
  • 三、wait、join、sleep 归纳

一、初识 wait、notify、notifyAll

我们知道由于线程的抢占式执行导致线程之间的调度是随机的,无序的。但是在一些场景下我们有需要合理的协调多个线程的执行顺序。我们知道使用 join 可以控制线程执行顺序,但是 join 只能让一个线程执行完在执行另外一个线程,功能有限。因此我们引入了 waitnotify/notifyAll 这样一组API用来更灵活地控制线程执行的顺序。

举个例子:

针对上述情况,我们可以使用 wait/notify 有效解决:

假如张三发现ATM没钱,就(wait)释放锁走出ATM机,并进行阻塞等待(暂时不参与CPU调度,不参与锁竞争),直到有人向ATM机存钱后,此时时机成熟,就可以唤醒(notify)张三,继续参与ATM机锁竞争。

二、wait、notify、notifyAll 功能介绍

1、wait()

wait():发现条件不满足/时机不成熟,就调用 wait() 阻塞等待,同时释放当前锁,当满足一定条件时可以被唤醒,重新尝试获取这个锁。

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

wait等待结束条件:

  1. 其他线程调用该对象的 notify 方法.
  2. wait 等待时间超时 (wait 方法提供一个带有 timeout 参数的版本, 来指定等待时间).
  3. 其他线程调用该等待线程的 interrupted 方法, 导致 wait 抛出 InterruptedException 异常.

2、notify()

notify():其他线程构造了一个成熟的条件,就可以调用 notify() 唤醒它。

notify注意事项:

  1. 方法notify()也要在同步方法或同步块中调用,该方法是用来通知那些可能等待该对象的对象锁的其它线程,对其发出通知notify,并使它们重新获取该对象的对象锁。
  2. 如果有多个线程等待,则有线程调度器随机挑选出一个呈 wait 状态的线程。(并没有 “先来后到”)
  3. 在notify()方法后,当前线程不会马上释放该对象锁,要等到执行notify()方法的线程将程序执行 完,也就是退出同步代码块之后才会释放对象锁。

3、notifyAll()

notifyAll():notify() 只是唤醒某一个等待线程。使用 notifyAll() 可以一次唤醒所有的等待同一对象的线程。

notifyAll注意事项:

虽然是同时唤醒 多个线程, 但是这 多个线程需要竞争锁,所以并不是同时执行,而仍然是先获取锁的先执行。

4、wait、notify、notifyAll 要点总结

  1. wait/notify/notifyAll 都是Object 的方法,因此只要是个类对象都可以使用 wait、notify、notifyAll。
  2. wait/notify/notifyAll 要搭配 synchronized 来使用. 脱离 synchronized 使用会直接抛出异常:IllegalMonitorStateException
  3. synchronized 的锁对象必须和调用 wait/notify/notifyAll 方法的对象是同一个。
  4. 针对某一加锁对象,先执行wait 然后 notify/notifyAll,此时才有效果,如果没有 wait 就 notify 相当于“一炮打空”,此时 wait 无法唤醒,不过代码不会出现其他异常。

5、wait/notify 使用示例

public class ThreadExample_wait_notify {
    public static void main(String[] args) throws InterruptedException {
        Object object = new Object();
        Thread t1 = new Thread(()->{
           synchronized (object) {
               try {
                   System.out.println("wait开始");
                   object.wait();
                   System.out.println("wait结束");
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
        });

        Thread t2 = new Thread(()->{
           synchronized (object) {
               System.out.println("notify开始");
               object.notify();
               System.out.println("notify结束");
           }
        });
        // 等待t1中wait解锁阻塞,否则t2中的notify没有实质效果
        t1.start();
        Thread.sleep(1000);
        t2.start();
    }
}

结果说明:

上述代码 t1 先获取到锁,执行到 wait 时 t1阻塞解锁,1秒后,t2获得锁,执行到 notify 时 t1 线程就会被唤醒,但是notify后不会立即释放锁,当 t2 代码块中的逻辑执行完后才释放锁,t1 线程才能获取锁继续向下执行。

三、wait、join、sleep 归纳

(1)wait
wait()方法是 Object类 提供的实例方法,可以使线程进入等待状态,直到其他线程调用了该对象的notify()或notifyAll()方法。通常被用于线程间通信,如生产者-消费者模式中(后续介绍),消费者需要等待生产者通知有新数据可取。当线程调用 wait() 方法时,它会释放占据的锁,并且线程的状态为WAITING,直到notify()或notifyAll()方法被调用。

(2)join
join() 方法是 Thread类 提供的方法静态方法,用于等待被调用线程执行完毕。在主线程中调用了子线程的join() 方法后,主线程会进入 WAITING 状态,直到子线程执行完毕才会继续执行。可以用来保证多个线程按照指定顺序执行。

(3)sleep
sleep()方法也是 Thread类 提供的实例方法,它可以使当前线程暂停执行一段时间。当线程调用 sleep() 方法时,它不会释放锁,线程的状态为 TIMED_WAITING 。通常被用于控制程序执行的速度或时间,或常常在循环内部以等待某些条件的发生。

总的来说,wait() 方法是用于线程间的通信join() 方法是用于等待其他线程执行完毕sleep()方法是用于暂停当前线程的执行。在使用上, wait 需要搭配 synchronized 使用,sleep 和 join 则不需要。总之本质上没有可比性,唯一的相同点就是都可以让线程放弃执行一段时间。它们的使用 场景 不同,需要根据实际需求选择合适的方法。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

QtConcurrent和QFuture的使用

在Qt中,有时候我们会遇到这样一种情况,需要执行一个很长时间的操作,这时候我们的主界面就会卡住。我们的通常做法就是把这个很长时间的操作扔到线程里去处理,可以使用标准库中的线程也可以使用QThread。 如果我们要在这个很长时间…

Java泛型机制

✅作者简介:大家好,我是Leo,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉 🍎个人主页:Leo的博客 💞当前专栏:每天一个知识点 ✨特色专栏&#xff1a…

javacv 基础04-读取mp4,avi等视频文件并截图保存图片到本地

javacv 读取mp4,avi等视频文件并截图保存图片到本地 代码如下: package com.example.javacvstudy;import org.bytedeco.javacv.FFmpegFrameGrabber; import org.bytedeco.javacv.Frame; import org.bytedeco.javacv.Java2DFrameConverter;import javax.imageio.Im…

单元测试:优雅编写Kotlin单元测试

一、MockK简介 MockK是一款功能强大、易于使用的Kotlin mocking框架。在编写单元测试时,MockK能够帮助我们简化代码、提高测试覆盖率,并改善测试的可维护性。除了基本用法外,MockK还提供了许多额外的功能和灵活的用法,让我们能够…

ARM DIY(四)WiFi 调试

文章目录 焊接打开内核编译选项重新编译内核烧录 && 运行 && 测试完善脚本测速手搓天线正式天线 焊接 换个粗点的风枪嘴,让热风覆盖 RTL8823BS 整体模块,最终实现自动归位 焊接 SDIO 接口的上拉电阻以及复位引脚上拉电阻 硬件部分就这…

linux centos7 bash中字符串反向输出

给定一个字符串,如何反向(倒序)输出? 字符串反转的方法:a.对各个字符位置进行循环调换(从原字符串左边取出放在新字符串的右边;从原字符串右边取出放在新字符串的左边)。b.对各个字符由水平排列转为垂直排…

时序预测 | MATLAB实现EEMD-SSA-LSTM、EEMD-LSTM、SSA-LSTM、LSTM时间序列预测对比

时序预测 | MATLAB实现EEMD-SSA-LSTM、EEMD-LSTM、SSA-LSTM、LSTM时间序列预测对比 目录 时序预测 | MATLAB实现EEMD-SSA-LSTM、EEMD-LSTM、SSA-LSTM、LSTM时间序列预测对比预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 时序预测 | MATLAB实现EEMD-SSA-LSTM、E…

渗透测试漏洞原理之---【失效的访问控制】

文章目录 1、失效的访问控制1.1、OWASP Top 101.1.1、A5:2017-Broken Access Control1.1.2、A01:2021 – Broken Access Control 1.2、失效的访问控制类别1.2.1、水平越权1.2.2、垂直越权 1.3、攻防案例1.3.1、Pikachu靶场 Over Permision1.3.2、DVWA越权利用失效的访问控制漏洞…

大数据课程K16——Spark的梯度下降法

文章作者邮箱:yugongshiyesina.cn 地址:广东惠州 ▲ 本章节目的 ⚪ 了解Spark的梯度下降法; ⚪ 了解Spark的梯度下降法家族(BGD,SGD,MBGD); ⚪ 掌握Spark的MLlib实现…

Data Rescue Professional for Mac:专业的数据恢复工具

在数字化时代,我们的生活和工作离不开电脑和存储设备。但是,意外情况时常发生,例如误删除文件、格式化硬盘、病毒攻击等,这些都可能导致重要的数据丢失。面对数据丢失,我们迫切需要一款可靠的数据恢复工具。今天&#…

剪枝基础与实战(5): 剪枝代码详解

对模型进行剪枝,我们只对有参数的层进行剪枝,我们基于BatchNorm2d对通道重要度 γ \gamma γ参数进行稀释训练。对BatchNorm2d及它的前后层也需要进行剪枝。主要针对有参数的层:Conv2d、BatchNorm2d、Linear。但是我们不会对Pool2d 层进行剪枝,因为Pool2d只用来做下采样,没…

在windows下进行maven安装配置

下载 https://maven.apache.org/download.cgi 安装配置 配置settings.xml文件 如果需要修改仓库的地址,可新增一条localRepository的记录,加上存放下载jar包的地址。 设置Maven镜像下载地址 配置完成,在命令行输入mvn help:system测试&#…

科创板50ETF期权交易:详细规则、费用、保证金和开户攻略

科创板50ETF期权是指以科创板50ETF为标的资产的期权合约。科创板50ETF是由交易所推出的一种交易型开放式指数基金(ETF),旨在跟踪科创板50指数的表现,下文介绍科创板50ETF期权交易:详细规则、费用、保证金和开户攻略&am…

uni-app中使用iconfont彩色图标

uni-app中使用iconfont彩色图标 大家好,今天我们来学习一下uni-app中使用iconfont彩色图标,好好看,好好学,超详细的 第一步 首先,从iconfont官网(iconfont-阿里巴巴矢量图标库)选择自己需要的图…

QT6为工程添加资源文件,并在ui界面引用

以添加图片资源为例 右键工程名字(不是最上面的名字),点击添加现有文件 这种方式虽然添加到了工程中,但不能在UI设计界面完成引用。主要原因可能是未把文件放入到项目资源文件中,以下面一种方式可以看出区别。 点击添…

FFmpeg报错:Connection to tcp://XXX?timeout=XXX failed: Connection timed out

一、现象 通过FFmpeg(FFmpeg的版本是5.0.3)拉摄像机的rtsp流获取音视频数据,执行命令: ./ffmpeg -timeout 3000000 -i "rtsp://172.16.17.156/stream/video5" 报错:Connection to tcp://XXX?timeoutXXX …

生态项目|Typus如何用Sui特性制作动态NFT为DeFi赋能

对于许多人来说,可能因其涉及的期权、认购和价差在内的DeFi而显得晦涩难懂,但Typus Finance找到了一种通过动态NFT使体验更加丰富的方式。Typus NFT系列的Tails为用户带来一个外观逐渐演变并在平台上提升活动水平时获得新特权的角色。 Typus表示&#x…

解决npm install报错: No module named gyp

今天运行一个以前vue项目,启动时报错如下: ERROR Failed to compile with 1 error上午10:19:33 error in ./src/App.vue?vue&typestyle&index0&langscss& Syntax Error: Error: Missing binding D:\javacode\Springboot-MiMall-RSA\V…

【数据结构】2015统考真题 6

题目描述 【2015统考真题】求下面的带权图的最小(代价)生成树时,可能是Kruskal算法第2次选中但不是Prim算法(从v4开始)第2次选中的边是(C) A. (V1, V3) B. (V1, V4) C. (V2, V3) D. (V3, V4) …

maven本地安装jar包install-file,解决没有pom的问题

背景: 公司因为权限问题,没有所有的代码,内部maven还在搭建,所以需要拿到同事的jar包,本地install: mvn install:install-file -DgroupIdcom..framework -DartifactIdcloud-api -Dversion1.0.0-SNAPSHOT …