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.hqwc.cn/news/527070.html

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

相关文章

C++ 多状态dp

目录 按摩师 打家劫舍 打家劫舍2 删除并获得点数 粉刷房子 按摩师 面试题 17.16. 按摩师 最大值问题 f : 预约此次的最长时间 g :不预约此次的最长时间 出现的错误:return max(f[n - 1]), g[n - 1]); 注意:①题目没给nums的范围&…

uniapp 云开发笔记

uniapp云开发官方文档https://uniapp.dcloud.io/uniCloud/learning.html 新建 关联云空间 云函数获取用户openID uniCloud API列表https://uniapp.dcloud.io/uniCloud/cf-functions.html#unicloud-api%E5%88%97%E8%A1%A8 自建云函数login event中包含前端传来的参数 uniCloud.…

Linux第74步_“设备树”下的LED驱动

使用新字符设备驱动的一般模板,以及设备树,驱动LED。 1、添加“stm32mp1_led”节点 打开虚拟机上“VSCode”,点击“文件”,点击“打开文件夹”,点击“zgq”,点击“linux”,点击“atk-mp1”&am…

使用阿里云服务器搭建网站教程,就这么简单!

使用阿里云服务器快速搭建网站教程,先为云服务器安装宝塔面板,然后在宝塔面板上新建站点,阿里云百科aliyunbaike.com以搭建WordPress网站博客为例,来详细说下从阿里云服务器CPU内存配置选择、Web环境、域名解析到网站上线全流程&a…

OS-Copilot:实现具有自我完善能力的通用计算机智能体

🍉 CSDN 叶庭云:https://yetingyun.blog.csdn.net/ AI 缩小了人类间的知识和技术差距 论文标题:OS-Copilot: Towards Generalist Computer Agents with Self-Improvement 论文链接:https://arxiv.org/abs/2402.07456 项目主页&a…

软件报错提示缺少D3DCompiler_47.dll文件怎么解决

许多用户在运行游戏或电脑软件时,遇到了一个提示“找不到d3dcompiler_47.dll”的错误消息。这个问题相当普遍,这个错误通常是由于系统中缺少关键的d3dcompiler_47.dll文件所导致的,而这个文件是很多应用程序运行的必要条件,特别是…

ES分页查询的最佳实践:三种方案

Elasticsearch(ES)中进行分页查询时,最佳实践取决于具体的使用场景和需求。 以下是对每种分页方法的简要分析以及它们适用的情况: 1. From Size 最常见且直观的方法,通过from参数指定跳过多少条记录,si…

【MySQL】表的增删改查——MySQL基本查询、数据库表的创建、表的读取、表的更新、表的删除

文章目录 MySQL表的增删查改1. Create(创建)1.1 单行插入1.2 多行插入1.3 替换 2. Retrieve(读取)2.1 select查看2.2 where条件2.3 结果排序2.4 筛选分页结果 3. Update(更新)3.1 更新单个数据3.2 更新多个…

【Python】time模块

专栏文章索引:Python 目录 一、介绍​编辑 二、常用函数​编辑 一、介绍 Python 的 time 模块提供了处理时间的函数。 二、常用函数 1.time():返回当前时间的时间戳(从1970年1月1日开始计时的秒数)。 import timecurrent_ti…

【Python数据结构与判断1/7】复杂的多向选择

目录 导入 举个栗子 代码优化 elif 栗子 执行顺序 情况一 情况二 情况三 if-elif-else特性 三种判断语句小结 if if-else if-elif-else 嵌套语句 if嵌套 栗子 执行顺序 相互嵌套 Tips Debug 总结 导入 在前面,我们学习了单向选择的if语句和多项…

人才推荐 | 高级半导体工艺工程师,美国凯斯西储大学电化学博士

编辑 / 木子 审核 / 朝阳 伟骅英才 伟骅英才致力于以大数据、区块链、AI人工智能等前沿技术打造开放的人力资本生态,用科技解决职业领域问题,提升行业数字化服务水平,提供创新型的产业与人才一体化服务的人力资源解决方案和示范平台&#x…

《深度学习风暴:掀起智能革命的浪潮》

在当今信息时代,深度学习已经成为科技领域的一股强大力量,其应用领域涵盖了从医疗到金融再到智能交互等方方面面。随着技术的不断进步和应用的不断拓展,深度学习的发展势头愈发迅猛,掀起了一股智能革命的浪潮。本文将从基本原理、应用实例、挑战与未来发展方向、与机器学习…