【Java】多线程-wait/notify

1、wait和notify

Java的多线程中,线程的执行顺序和时间都是不定的。为了控制线程的调度顺序,前面我们引入了join()方法。

但是join()只能在线程执行完后,才能执行其他线程,有没有什么方法可以在线程执行顺序中来调度其他线程呢?

这里我们引入了wait()和notify()方法

wait()、notify()和notifyAll()都是属于Object类中的方法,任何对象都可以调用这几个方法

wait()/wait(time):让当前进程进入阻塞状态

notify()/notifyAll():唤醒当前对象上等待的对象

wait()的基本用法是

Object object = new Object();
synchronized (object){try {object.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}

notify()基本用法

synchronized (object){object.notify();
} 

2、注意事项

(1)wait()和notify()在使用时都要加锁

在使用上述三个方法时,需要对竞争资源进行加锁,不然就会报错

并且wait()方法在使用时,线程必须获得锁对象的控制权

(2)阻塞状态

线程调用wait()方法后,线程进入阻塞状态(WAITING

阻塞状态什么也不做,不会占用CPU

 

(3) notify的调用位置

对象调用wait方法后,对象锁被释放,这时必须由其他线程来唤醒对象

如果将notify写在同一线程中,则不能唤醒当前对象

public class demo {public static void main(String[] args) {Object object = new Object();System.out.println("开始进程");synchronized (object){try {object.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}object.notify();}System.out.println("结束进程");}
}

线程会继续阻塞 

3、wait()带参数方法和notifyAll()

 (1)wait()带参数方法

 wait(long timeout)中的参数表示线程阻塞的超时时间,如果超过这个时长,那么线程会被自动唤醒

避免无休止地等待下去

public class demo {public static void main(String[] args) {Object object = new Object();Thread thread1 = new Thread(()->{synchronized (object){System.out.println("线程1开始执行");try {object.wait(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("线程1执行结束");}});Thread thread2 = new Thread(()->{System.out.println("线程2开始执行");System.out.println("线程2执行结束");});thread1.start();thread2.start();}
}

上述代码中,并没有对线程1进行唤醒操作,而是在1000ms的等待时间结束后,线程1自动唤醒,打印结果并结束线程 

(2)notifyAll() 

notify()一次唤醒一个线程,notifyAll() 一次唤醒全部线程

由于唤醒线程的过程中也要进行锁的竞争,因此notifyAll()的唤醒并不是并行执行,而是串行执行的

 · 多次notify()唤醒多个线程

public class demo {public static void main(String[] args) {Object object = new Object();Thread thread1 = new Thread(()->{synchronized (object){System.out.println("线程1开始执行");try {object.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("线程1拿回锁");System.out.println("线程1执行完毕");}});Thread thread2 = new Thread(()->{synchronized (object){System.out.println("线程2开始执行");try {object.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("线程2拿回锁");System.out.println("线程2执行完毕");}});Thread thread3 = new Thread(()->{try {Thread.sleep(2000);} catch (InterruptedException e) {throw new RuntimeException(e);}synchronized (object){System.out.println("线程3开始执行");object.notify();object.notify();System.out.println("线程释放锁");System.out.println("线程3执行完毕");}});thread1.start();thread2.start();thread3.start();}
}

线程3唤醒两次,使得线程1和线程2先后拿回锁

 · notifyAll() 

public class demo {public static void main(String[] args) {Object object = new Object();Thread thread1 = new Thread(()->{synchronized (object){System.out.println("线程1开始执行");try {object.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("线程1拿回锁");System.out.println("线程1执行完毕");}});Thread thread2 = new Thread(()->{synchronized (object){System.out.println("线程2开始执行");try {object.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("线程2拿回锁");System.out.println("线程2执行完毕");}});Thread thread3 = new Thread(()->{try {Thread.sleep(2000);} catch (InterruptedException e) {throw new RuntimeException(e);}synchronized (object){System.out.println("线程3开始执行");object.notifyAll();System.out.println("线程释放锁");System.out.println("线程3执行完毕");}});thread1.start();thread2.start();thread3.start();}
}

执行结果

 

3、关于锁释放的时间

在线程2唤醒 线程1后,线程2会立即释放锁吗?

我们通过一段代码来验证一下

public class demo {public static void main(String[] args) {Object object = new Object();Thread thread1 = new Thread(()->{synchronized (object){System.out.println("线程1开始执行");try {object.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("线程1拿回锁");System.out.println("线程1执行结束");}});Thread thread2 = new Thread(()->{synchronized (object){System.out.println("线程2拿到锁");System.out.println("线程2开始执行");System.out.println("线程2释放锁");object.notify();try {Thread.sleep(2000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("线程2执行结束");}});thread1.start();thread2.start();}
}

上述代码执行结果为:

可以看到,在线程2调用notify()唤醒线程1后,就算进行了休眠,也并没有释放锁;而是在线程2的代码全部执行完后,线程2才释放锁

所以,我们可以得出的结论是:在一个线程唤醒其他线程后,它不会立即释放锁,而是要在本线程代码执行完后才释放锁 

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

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

相关文章

CTF-PWN-小tips

文章目录 overflowscanfgetreadstrcpystrcat Find string in gdbgdbgdb peda Binary ServiceFind specific function offset in libc手工自动 Find /bin/sh or sh in library手动自动 Leak stack addressFork problem in gdbSecret of a mysterious section - .tlsPredictable …

【腾讯云 HAI域探秘】高性能服务器引领AI革新浪潮:从AI绘画、知识问答到PyTorch图像分类、视频检测的全方位探索

目录 1 HAI(高性能应用服务)简介2 HAI的应用场景2.1 HAI在AI作画中的灵活性与效率2.2 深入探索LLM语言模型的应用与性能2.3 HAI支持的AI模型开发环境与工具 3 基于stable difussio的AI 绘画应用实践3.1 使用AI模型中的stable diffusion模型服务3.2 设置和…

10个好用的Mac数据恢复软件推荐—恢复率高达99%

如果您正在寻找最好的 Mac 数据恢复软件来检索意外删除或丢失的文件,那么这里就是您的最佳选择。 我们理解,当您找不到 Mac 计算机或外部驱动器上保存的一些重要文件时,会感到多么沮丧和绝望。这些文件非常珍贵,无论出于何种原因…

【寒武纪(14)】硬件系统由标量指令、向量指令、张量指令、访存指令构成

我们在文档《Cambricon-BANG-C-Developer-Guide-EN-v4.5.1》的build-in function 发现,存在三种计算:矩阵乘法、标量类型、向量。 查阅《Cambricon-BANG-C-CProgramming-Guide-CN-v1.5.0.pdf》可知,硬件系统由标量指令、向量指令、张量指令、…

vscode设置前进、后退快捷键

前言 在我们使用vscode编写程序时,经常需要在不同的文件之间跳来跳去,如果只是依靠个人记忆去操作会显得非常不方便。本文介绍如何设置vscode的前进、后退快捷键。 1 vscode设置前进、后退快捷键 点击“设置”图标,然后点击“键盘快捷方式…

各类软件docker安装

docker Docker 要求 CentOS 系统的内核版本高于 3.10 ,通过 uname -r 命令查看你当前的内核版本: uname -r 3.10.0-1062.1.2.el7.x86_64 安装 Docker: 安装 Docker:yum -y install dockerkafka和zookeeper docker pull wurstmei…

python刷题笔记1(42例题)

1. split()函数 str.split([sep [, maxsplit]]) 分割字符串,返回一个数组 2. 判断子串 # 判断子串是否在主串里面,是则输出“Yes”,否则输出“No” str1 input("子串:") str2 input("主串:") if str1 in s…

通信原理板块——差错控制编码或纠错编码

微信公众号上线,搜索公众号小灰灰的FPGA,关注可获取相关源码,定期更新有关FPGA的项目以及开源项目源码,包括但不限于各类检测芯片驱动、低速接口驱动、高速接口驱动、数据信号处理、图像处理以及AXI总线等 1、背景 数字信号在传输过程中&…

什么是策划能力?如何提高策划能力?

什么是策划能力? 通常我们理解的策划能力,大多指的是策划活动,比如举办一次活动先要进行活动策划,形成具体的行动方案,然后开展组织人力物力等资源,最终落地实施。策划能力包含活动策划,但又不…

vscode设置代码模板

一键生成vue3模板代码 效果演示 输入vue3 显示快捷键 按回车键 一键生成自定义模板 实现方法 进入用户代码片段设置 选择片段语言 vue.json输入自定义的代码片段 prefix是触发的内容,按自己的喜好来就行; body是模板代码,写入自己需要的…

UE TransformVector 学习笔记

假如算现在枪的位置,那么就是先拿人的位置再拿枪在本地的相对位置相加,就是枪的位置,也就是枪在场景中的位置,那么这里还可以写成Actor的变化和枪的相对位置连在TransformVector上,返回的就是枪的场景位置 这里做反算&…

会议剪影 | 思腾合力受邀出席第四届长三角文博会并作主题演讲

以“担当新使命:长三角文化产业的力量”为主题的「第四届长三角国际文化产业博览会」于2023年11月16日-19日在国家会展中心(上海)成功举办。思腾合力作为行业领先的人工智能基础架构解决方案商出席本次盛会。 此次展会的面积首次超过10万平米&#xff0c…

BUUCTF 菜刀666 1

BUUCTF:https://buuoj.cn/challenges 题目描述: 流量分析,你能找到flag吗 注意:得到的 flag 请包上 flag{} 提交 密文: 下载附件,解压得到一个.pcapng文件。 解题思路: 1、双击文件,打开wir…

算法-简单-二叉树-翻转、对称

记录一下算法题的学习8 翻转二叉树 翻转二叉树题目 给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。 举例:给定root[5,3,7,2,4,6,10] 翻转成为root[5,7,3,10,6,4,2] 即所有的根节点的左右节点都要互换位置,输出的…

Python如何将项目直接打包为一键整合包

目录 一、准备项目 二、创建打包文件 三、创建安装脚本 四、执行安装 五、测试安装 六、常见问题与解决方案 总结 Python项目打包成一键整合包是一个比较复杂的任务,需要考虑到项目的各个方面,包括依赖项、配置文件、静态文件、数据库等等。下面是…

NX二次开发UF_CAM_ask_tool_matl_db_object 函数介绍

文章作者:里海 来源网站:里海NX二次开发3000例专栏 UF_CAM_ask_tool_matl_db_object Defined in: uf_cam.h int UF_CAM_ask_tool_matl_db_object(UF_CAM_db_object_t * db_obj ) overview 概述 This function provides the database object which is…

NX二次开发UF_CAM_ask_lower_limit_plane_status 函数介绍

文章作者:里海 来源网站:里海NX二次开发3000例专栏 UF_CAM_ask_lower_limit_plane_status Defined in: uf_cam_planes.h int UF_CAM_ask_lower_limit_plane_status(tag_t object_tag, UF_PARAM_lwplane_status_t * status ) overview 概述 Query the…

NX二次开发UF_CAM_ask_opt_template_object 函数介绍

文章作者:里海 来源网站:里海NX二次开发3000例专栏 UF_CAM_ask_opt_template_object Defined in: uf_cam.h int UF_CAM_ask_opt_template_object(UF_CAM_opt_t * opt_object ) overview 概述 This function provides the object which is used to in…