Java EE之wait和notify

一.多线程的执行顺序

由于多个线程执行是抢占式执行,就会导致顺序不同,同时就会导致出现问题,就比如俩个线程同时对同一个变量进行修改,我们难以预知执行顺序。

但在实际开发中,我们希望代码按一定的逻辑顺序执行,希望可以协调多个线程的执行顺序。

之前提到过join,会让调用它的线程进入阻塞等待,但有个缺陷就是,它必须得等那个线程完全执行完才能继续执行。怎么才能随意调度?

可以用到wait和notify方法

二.wait和notify

1.wait和notify可以协调多个线程的执行顺序

wait可以让指定线程进入阻塞等待状态,notify可以唤醒正在wait的线程

2.wait和notify是依赖对象的

wait和notify都是Object类里面的成员方法,它们的调用是依赖对象的

3.wait所做的工作

在了解wait所做的工作之前,我们先看一个wait和notify使用的实例:

我们发现唤醒wait之后,没有进行打印操作,而是抛出了异常,这个异常叫做:IllegalMonitorStatementException非法的监视器状态异常,什么是监视器?其实这里说的是synchronized锁,它也叫做监视器锁。这里我们就可以来了解一下wait所作的工作:

1.释放当前所持有的锁

2.让线程进入阻塞状态,并等待被唤醒。

3.当线程被唤醒时,重新获取到锁

所以说,使用wait的前提是得加锁,同时notify也得加锁,对谁加锁?就是对调用wait和notify的哪个对象进行加锁。

为什么要这样加锁呢?首先对线程1进行加锁,当它不想做任何事情时,就进入阻塞状态,此时它啥也不干,就没必要拿着锁,就释放了,让急需锁的线程2先用,当线程2的任务完成的差不多时,他就可以把锁还给线程1了。所以代码修改如下:

4.notify

唤醒正在等待的线程。当有多个线程都在等待时(前提是这几个等待的线程都在等待同一把锁),notify唤醒时是随即唤醒其中的一个线程而其他线程还在等待。并且,如果notify后面还有代码(在synronized里面),就会先执行完这些代码,再唤醒wait的线程如下例子:

public class Test2 {private static Object object=new Object();public static void main(String[] args) {Thread t1=new Thread(()->{synchronized(object) {System.out.println("t1kaishi");try {object.wait();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("t1jieshu");}});Thread t2=new Thread(()->{synchronized (object){System.out.println("t2kaishi");try {object.wait();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("t2jieshu");}});Thread t3=new Thread(()->{try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (object){try {object.notify();Thread.sleep(1000);System.out.println("t3jieshu");} catch (InterruptedException e) {e.printStackTrace();}}});t1.start();t2.start();t3.start();}
}

首先,t1t2是等待线程,t3是通知线程。t1开始,先得到了锁,然后wait时释放了锁,这时t2拿到了锁,然后wait时释放了锁;之后等1秒过后,t3拿到了锁,然后唤醒等待该锁的线程,但我们发现,最终是t1结束了,但t2没有结束而且程序迟迟没有结束,这说明只有t1被唤醒了,而t2还在wait。而且可以发现,是t3结束先打印的,说明是notify之后会把后面的代码全部执行完才会去唤醒线程,而在调用了notify和t3后续代码执行完期间,t1的状态就是BLOCKED状态,如下:

这是在t3执行了notify之后,t1的状态:Thread-2(也就是t3)持有锁,而Thread-0(t1)已经不是waiting状态了,而是BOLCKED状态,它已经被唤醒,在等锁。

5.notifyAll

notifyAll方法是一次唤醒所有线程。这与notify不同的是,所有线程都可以从WAITING状态转变成其他状态,但是,一i那位它们都想拿同一把锁,所以会出现锁金正,没拿到锁的就得等待持有锁的把锁释放了再去竞争,在等待锁的过程中,这些线程就是BLOCKED状态

public class Test2 {private static Object object=new Object();public static void main(String[] args) {Thread t1=new Thread(()->{synchronized(object) {System.out.println("t1kaishi");try {object.wait();Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("t1jieshu");}});Thread t2=new Thread(()->{synchronized (object){System.out.println("t2kaishi");try {object.wait();Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("t2jieshu");}});Thread t3=new Thread(()->{try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (object){try {object.notifyAll();Thread.sleep(1000);System.out.println("t3jieshu");} catch (InterruptedException e) {e.printStackTrace();}}});t1.start();t2.start();t3.start();}
}

还是上面这个代码,只不过在t1t2被唤醒后又让它们沉睡了1秒,以便观察它们的状态,这一次是notify之后,t2抢到了锁,观察jconsole.exe,发现t1和t2都是BLOCKED,因为先执行了t3锁里面的内容,然后是t2开始执行,此时t1还是BLOCKED,最后t1也拿到了锁。

6.注意

一般我们使用nootify方法,而不是用notifyAll方法,因为notify方法更加可控,而notifyAll方法却会引起竞争,而且会增加cpu的消耗

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

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

相关文章

计算机视觉——P2PNet基于点估计的人群计数原理与C++模型推理

简介 人群计数是计算机视觉领域的一个核心任务,旨在估算静止图像或视频帧中的行人数量。在过去几十年中,研究人员在这个领域投入了大量的精力,并在提高现有主流基准数据集性能方面取得了显著进展。然而,训练卷积神经网络需要大规…

matlab阶段学习笔记小节2

syms定义符号变量 求极限 第二题 第三题 limit(y,n,inf);求的的函数y关于自变量n在无穷处(inf)的极限 exp(2)即指数为2,底为e,也就是e^2 求导数 第一题 log(x)默认是以e为底的指数函数,也就是ln(x). 使用diff(f)对函数进行求…

算法-双指针、BFS与图论-1113. 红与黑

题目 思路 本题相当于问BFS中的当前点所在的区域连通块有多少个 Flood Fill算法 (可参考以下链接:洪水覆盖算法(Flood Fill):颜色填充-CSDN博客)本题用DFS实现Flood Fill算法DFS是否需要恢复现场:(重要&am…

新IDEA电脑环境设置

1.设置UTF-8 2.Maven 3.JRE选对

【漏洞复现】华三用户自助服务产品dynamiccontent.properties.xhtml接口处存在RCE漏洞

免责声明:文章来源互联网收集整理,请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失,均由使用者本人负责,所产生的一切不良后果与文章作者无关。该…

VUE+HBuilder的uniapp技术路线开发应用使用总结

使用总结 本来想做一个记录日常数据的应用,主要在Android端使用,后来发现在uniapp中使用sqllite数据库不是像原生中那样简单(所以当前准备去进行另一个路线,就是给我使用的电脑都安装一个portalble的服务端,用来记录数据&#xf…

java中使用rabbitmq

文章目录 前言一、引入和配置1.引入2.配置 二、使用1.队列2.发布/订阅2.1 fanout(广播)2.2 direct(Routing/路由)2.3 Topics(主题)2.4 Headers 总结 前言 mq常用于业务解耦、流量削峰和异步通信,rabbitmq是使用范围较广,比较稳定的一款开源产品,接下来我们使用springboot的sta…

角蜥优化算法 (Horned Lizard Optimization Algorithm ,HLOA)求解无人机路径优化

一、无人机路径规划模型介绍 无人机三维路径规划是指在三维空间中为无人机规划一条合理的飞行路径,使其能够安全、高效地完成任务。路径规划是无人机自主飞行的关键技术之一,它可以通过算法和模型来确定无人机的航迹,以避开障碍物、优化飞行时间和节省能量消耗。 二、算法介…

数据结构:图及相关算法讲解

图 1.图的基本概念2. 图的存储结构2.1邻接矩阵2.2邻接表2.3两种实现的比较 3.图的遍历3.1 图的广度优先遍历3.2 图的深度优先遍历 4.最小生成树4.1 Kruskal算法4.2 Prim算法4.3 两个算法比较 5.最短路径5.1两个抽象存储5.2单源最短路径--Dijkstra算法5.3单源最短路径--Bellman-…

Dataset 读取数据

Dataset 读取数据 from torch.utils.data import Dataset from PIL import Image import osclass Mydata(Dataset):def __init__(self,root_dir,label_dir):self.root_dir root_dir #根目录 dataset/trainself.label_dir label_dir #标签的后面链接目录 ants_ima…

windows系统玩游戏找不到d3dx9_43.dll缺失,无法启动此程序的解决方法

今日,我们要深入讨论d3dx9_43.dll文件的重要性及其缺失问题。最近,我也遇到了这个文件丢失的困扰,因此想借此机会与大家分享如何解决d3dx9_43.dll缺失的问题。 一.电脑d3dx9_43.dll丢失会提示什么? 关于电脑提示d3dx9_43.dll丢失…

神经网络实战前言

应用广泛 从人脸识别到网约车,在生活中无处不在 未来可期 无人驾驶技术便利出行医疗健康改善民生 产业革命 第四次工业革命——人工智能 机器学习概念 机器学习不等价与人工智能20世纪50年代,人工智能是说机器模仿人类行为的能力 符号人工智能 …

【环境配置】Linux MySQL8 忘记密码解决措施

本片博客介绍 Linux 操作系统 Ubuntu 下,MySQL8 忘记密码怎么重新设置,笔者亲测有效,分享给大家。 查看 MySQL 版本 $ mysql --version停止 MySQL 服务器,并查看状态是否变更为 Server shutdown complete # 等价命令sudo syste…

Django简易用户登入系统示例

Django简易用户登入系统示例 1)添加url和函数的对应关系(urls.py) urlpatterns [ path(login/, views.login), #login:url路径,views.login:对应的函数 ]2)添加视图函数(views.py) def login(req):if…

IDEA + Git + GitHub(保姆级教学)

文章目录 IDEA Git GitHub1.IDEA克隆远程仓库到本地仓库1.创建一个GitHub远程仓库test12.IDEA克隆仓库到本地1.复制远程仓库地址2.创建一个版本控制项目3.克隆到本地仓库4.克隆成功 2.IDEA将本地项目push到远程仓库1.在这个项目下新建一个java模块1.新建模块2.填写模块名3.在…

【CSP试题回顾】202006-1-线性分类器

CSP-202006-1-线性分类器 解题思路 线性分类问题,即根据给定的数据点和分类界限,判断是否存在一条线能够将属于不同类别的点完全分开。具体来说,数据点被分为两类,标记为A和B,我们要找出是否存在一个线性决策边界&…

gpt不能发送信息了?

文章目录 问题注意步骤解决后 问题 注意步骤 清理所有cookie和浏览数据,可保存密码 解决后

C++的类与对象(五):赋值运算符重载与日期类的实现

目录 比较两个日期对象 运算符重载 赋值运算符重载 连续赋值 日期类的实现 Date.h文件 Date.cpp文件 Test.cpp文件 const成员 取地址及const取地址操作符重载 比较两个日期对象 问题描述:内置类型可直接用运算符比较,自定义类型的对象是多个…

虚拟 DOM:前端性能优化的秘密

🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…

【大厂AI课学习笔记NO.72】AI与云计算

AI项目依靠云计算,借助云的力量,快速的启动业务,是比较好的一种选择。 AI模型训练过程中,出现算力突增,云计算成本低。 云平台提供一站式解决方案,创业公司的选择。 云端AI和边缘端的AI,是我们…