wait 和 notify

由于线程之间是抢占式执行的, 因此线程之间执行的先后顺序难以预知。但是实际开发中有时候我们可以通过一些 api 让线程主动阻塞,从而控制多个线程之间的执行先后顺序.

完成这些操作就需要用到 wait,notify / notifyAll

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

wait()方法

某个线程调用 wait 方法,就会进入阻塞(无论是通过哪个对象 wait 的),此时就处在 WAITING

wait 做的事情

1. 释放当前的锁

2. 进行阻塞等待

3. 收到通知后, 重新尝试获取这个锁.

        因此 wait 要搭配 synchronized 来使用. 脱离 synchronized 使用 wait 会直接抛出异常(没锁怎么解锁)。

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

        这样在执行到object.wait()之后就一直等待下去,但程序肯定不能一直这么等待下去。这个时候就需要使用到了另外一个方法唤醒了,notify()。

notify()方法

notify 方法是唤醒等待的线程 

public class ThreadDemo17 {public static void main(String[] args) throws InterruptedException {Object object = new Object();Thread t1 = new Thread(() -> {// 这个线程负责进行等待System.out.println("t1: wait 之前");try {synchronized (object) {object.wait();}} catch (InterruptedException e) {e.printStackTrace();}System.out.println("t1: wait 之后");});Thread t2 = new Thread(() -> {System.out.println("t2: notify 之前");synchronized (object) {// notify 务必要获取到锁, 才能进行通知try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}object.notify();}System.out.println("t2: notify 之后");});t1.start();// 此处写的 sleep 500 是大概率会让当前的 t1 先执行 wait 的.// 极端情况下 (电脑特别卡的时候), 可能线程的调度时间就超过了 500 ms// 还是可能 t2 先执行 notify.Thread.sleep(500);t2.start();}
}

        如果 t2 不进行 notify ,此时 t1就会一直等。因此 wait 也提供了一个带参数的版本,可以指定最大等待时间。

        这个带有等待时间的版本和 sleep 有点像。他们都能指定等待时间,也都能被提前唤醒 wait 是使用 notify 唤醒,sleep 是使用 interrupt 唤醒,但这里的含义却截然不同。notify 唤醒 wait 不会有任何异常;interrupt 唤醒 sleep 则是出异常了。

        如果有多个线程等待 object 对象,此时只有一个线程 object.notify(),会随机唤醒一个等待的线程(不知道具体哪个)。但是可以用多组不同的对象来唤醒指定的线程。

        在notify()方法后,当前线程不会马上释放该对象锁,要等到执行notify()方法的线程将程序执行完,也就是退出同步代码块之后才会释放对象锁。

public class ThreadDemo18 {// 有三个线程, 分别只能打印 A, B, C. 控制三个线程固定按照 ABC 的顺序来打印.public static void main(String[] args) throws InterruptedException {Object locker1 = new Object();Object locker2 = new Object();Thread t1 = new Thread(() -> {System.out.println("A");synchronized (locker1) {locker1.notify();}});Thread t2 = new Thread(() -> {synchronized (locker1) {try {locker1.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("B");synchronized (locker2) {locker2.notify();}});Thread t3 = new Thread(() -> {synchronized (locker2) {try {locker2.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("C");});t2.start();t3.start();//这样子是为了防止 t1 先通知了,t2 和 t3 就会死等Thread.sleep(100);t1.start();}
}

wait 结束等待的条件

其他线程调用该对象的 notify 方法.

wait 等待时间超时 (wait 方法提供一个带有 timeout 参数的版本, 来指定等待时间).

其他线程调用该等待线程的 interrupted 方法, 导致 wait 抛出 InterruptedException 异常.

       P 打算去 ATM 上取点钱,但是这时候显示没钱了,这时候 P 就要出去等在外面排队的人进去查余额、存款、转账......结果在排队的人都是取钱的,这时候运钞车就来了,工作人员把钱放进去之后说:可以了。这时候就通知了外面的人可以取钱了,先进去取的人就结束等待,没进去的人只能在外面阻塞。

notifyAll()方法

        和 notify 非常相似。多个线程 wait 的时候,notify 是随机唤醒一个,notifyAll 是所有的线程都唤醒,然后这些线程再一起竞争锁。

notify 只唤醒等待队列中的一个线程. 其他线程还是乖乖等着

notifyAll 一下全都唤醒, 需要这些线程重新竞争锁

wait sleep 的对比(面试题)

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

当然为了面试的目的,我们还是总结下:

1. wait 需要搭配 synchronized 使用. sleep 不需要.

2. wait 是 Object 的方法 sleep 是 Thread 的静态方法.

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Collection与数据结构 二叉树(一):二叉树的性质与基本操作

1. 树形结构 1.1 概念1 (了解) 树是一种非线性的数据结构,它是由n(n>0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点&#…

HTTPS,不可或缺的数据安全锁

互联网时代的发展,让我们足不出户就能办理很多生活和工作上的事情,便利了我们的工作和生活。随着网络技术的不断升级,网络安全已经成为当下的焦点,如何让互联网为我们提供服务的同时也能保护好用户的隐私,已经成为行业…

Spring 之 IoC概述

目录 1. IoC概述 1.1 控制反转 1.2 依赖注入 2. IoC容器在Spring中的实现 2.1 BeanFactory 2.2 ApplicationContext 2.2.1 ApplicationContext的主要实现类 1. IoC概述 全称:Inversion of Control,译为 “控制反转” Spring通过IoC容器来管理所有…

运筹学基础(六)列生成算法(Column generation)

文章目录 前言从Cutting stock problem说起常规建模Column generation reformulation 列生成法核心思想相关概念Master Problem (MP)Linear Master Problem (LMP)Restricted Linear Master Problem (RLMP)subproblem(核能预警,非常重要) 算法…

学习嵌入式可以胜任哪一些行业?

嵌入式技术之应用范围甚广,其多见于机器人、无人机、医疗器械以及军工等领域,为学习者带来诸多广泛之职业机遇。嵌入式工程师于此诸领域中扮演关键之角色,负责解决硬件平台适配等诸问题,以为创新提供支撑之力。 虽嵌入式技术与日…

实验案例一:交换机的初始配置

1、实验环境 实验用具包括一台 Cisco 交换机,一台 PC,一根 Console 线缆。 2、需求描述 如图 5.17 所示,实验案例一的配置需求如下。 通过 PC 连接并配置一台 Cisco 交换机在交换机的各个配置模式之间切换将交换机主机的名称改为 BDON 3、…

flutter滑动隐藏头部

模型代码 import packagegenerated/l10n.dart; import package:jade/bean/TabTypeMode.dart; import package:jade/customWidget/MyCustomIndicator.dart; import package:jade/experienceStationCreate/MyExpCellBillHistory.dart; import package:jade/utils/JadeColors.dar…

【Linux 学习】进程优先级和命令行参数!

1. 什么是优先级? 指定进程获取某种资源(CPU)的先后顺序; Linux 中优先级数字越小,优先级越高; 1.1 优先级和权限的区别? 权限 : 能不能做 优先级: 已经能了,但是获…

1653. 使字符串平衡的最少删除次数

1653. 使字符串平衡的最少删除次数 题目 链接&#xff1a;使字符串平衡的最少删除次数 题解 class Solution {public int minimumDeletions(String s) {int left0,right0;int ns.length();for(int i0;i<n;i){if(s.charAt(i)a){right;}}int resright;for(int i0;i<s.…

STM32学习笔记(11_1)- SPI简介和工作原理

无人问津也好&#xff0c;技不如人也罢&#xff0c;都应静下心来&#xff0c;去做该做的事。 最近在学STM32&#xff0c;所以也开贴记录一下主要内容&#xff0c;省的过目即忘。视频教程为江科大&#xff08;改名江协科技&#xff09;&#xff0c;网站jiangxiekeji.com 本期学…

Pytest接口自动化测试进阶

背景 随着Web应用的发展&#xff0c;越来越多的功能需要用户登录才能使用。而在接口测试中&#xff0c;往往需要模拟用户的登录状态来进行测试。一种常见的做法是通过Cookie来维持用户的登录状态。然而&#xff0c;由于Cookie的有效期限制以及网站的安全策略&#xff0c;如何在…

YOLOv5标签值含义根据标签将检测框色块替换(马赛克)

以一个检测人脸的图片为例&#xff1a; 检测后生成的标签txt如下&#xff0c; 此时&#xff0c;如何根据标签值将检测到的人脸同色块替换呢&#xff1f; 关键是获取检测框的左上角坐标和右下角坐标。 img Image.open(D:/PythonWokspace/JINX/datasets_transform/dataset/im…