当前位置: 首页 > news >正文

Java 多线程 --- 线程协作 wait/notify

Java 多线程 --- 线程协作 wait/notify

  • wait / notify
  • Object.wait() , Object.notify() / notifyAll()
  • notify 和 wait 的原理
  • notify会导致死锁的问题
  • wait / notify的开销以及问题

wait / notify

  • 在多线程中, 如果程序拿到锁之后, 但是没有满足指定条件而不能继续往下执行, 我们可以将当前线程暂停(进入阻塞状态), 直到满足所需要的条件时再将线程唤醒, 结构如下:
atomic {while (条件 不成立) {wait //暂停当前线程}//执行目标动作doAction();notify
}
  • 上述操作必须是原子操作. 一个线程因其执行目标动作所需的条件为满足而被暂停的过程就是等待 (Wait)
  • 一个线程使用完critical section. 更新了系统的状态, 使得其他线程所需的保护条件得以,满足的时候唤醒那些被暂停的线程的过程就被称为通知 (Notify)

Object.wait() , Object.notify() / notifyAll()

  • Java中通过 Object.wait() 和 Object.notify() 实现等待和通知.
  • wait和notify都是Object的方法, 也就是每个对象都有wait和notify方法
  • wait()的作用是使正在执行的线程被阻塞
  • notify()的作用是唤醒一个被阻塞的线程.
  • notifyAll()的作用是唤醒全部被阻塞的线程
  • 具体格式如下
sychrnoized(lock) {while (条件 不成立) {lock.wait //暂停当前线程}//执行目标动作doAction();lock.notify
}

Example:

给你一个类:
public class Foo {public void first() { print("first"); }public void second() { print("second"); }public void third() { print("third"); }
}
三个不同的线程 ABC 将会共用一个 Foo 实例。线程 A 将会调用 first() 方法
线程 B 将会调用 second() 方法
线程 C 将会调用 third() 方法请设计修改程序,以确保 second() 方法在 first() 方法之后被执行,third() 方法在 second() 方法之后被执行。
public class Foo {private int flag = 0;//声明一个objetc作为锁private Object lock = new Object();public Foo() {}public void first(Runnable printFirst) throws InterruptedException {synchronized (lock){while( flag != 0){//还没有轮到自己运行, 进入阻塞状态. lock.wait();}printFirst.run();flag = 1;//唤醒其他在阻塞状态的线程lock.notifyAll();}}public void second(Runnable printSecond) throws InterruptedException {synchronized (lock){while (flag != 1){lock.wait();}printSecond.run();flag = 2;lock.notifyAll();}}public void third(Runnable printThird) throws InterruptedException {synchronized (lock){while (flag != 2){lock.wait();}printThird.run();flag = 0;lock.notifyAll();}}
}

notify 和 wait 的原理

  • 每个sychronizied锁(也就是内部锁), 都有一个monitor对象
  • monitor对象有三个部分
  • The Owner: 表示目前锁的持有者, 如果为null则表示是无锁状态
  • Entry Set: 记录等待获得相应内部锁的线程. 多个线程申请同一个锁的时候, 只有一个申请者能够成为该锁的持有线程, 其他申请失败者会继续保留在Entry Set.
  • Wait Set: 当一个线程获得锁之后, 因为没有满足某些条件而不得不放弃锁 (调用wait方法). 会被放入Wait Set并进入阻塞状态

在这里插入图片描述

  • 我们知道 Java 虛拟机会为每个锁(也就是对象)维护一个入口集(Entry Set )用于存储申请该对象的内部锁的线程。
  • 此外,Java 虛拟机还会为每个锁(也就是对象) 维护一个被称为等待集(Wait Set )的队列,该队列用于存储该对象上的等待线程。
  • wait方法会将当前线程放进 Wait Set, 并把当前线程变为阻塞状态
  • notify方法会使该对象的Wait Set中的一个任意线程被唤醒。注意此时线程不会释放锁, 要等待临界区运行完毕, 所以notify尽量放在临界区的末尾.
  • 被唤醒的线程仍然会停留在相应对象的Wait Set中,直到该线程再次竞争相应内部锁的时候, Object.wait会使当前线程从其所在的Wait Set中移除.(应该是不管竞争失败或者成功都会被移除, 不过这一点不确定)接着 Object.wait调用就返回了. (具体如伪代码所示)
  • Object. waito/notify()实现的等待/通知中的几个关键动作,包括将当前线程加入等待集, 暂停当前线程, 释放锁以及将唤醒后的等待线程从等待集中移除等,都是在 Obiect.wait() 中实现的.
  • Object. wait() 的部分内部实现相当于如下伪代码:
public void wait () {//执行线程必须持有当前对象对应的内部锁if (!Thread.holdsLock (this) ) {throws new IllegalMonitorStatefxception():}if (当前对象不在等待集中){//将当前线程加入当前对象的等待集中addToWaitSet(Thread.currentThread ());}atomic { //原子操作开始, 释放当前对象的内部锁releaselock(this) ://阻塞当前线程block(Thread. current Thread ());}//再次申请当前对象的内部锁acquireLock(this);//将当前线程从当前对象的等待集中移除removeFromWaitSet(Thread. currentIhread () ) ;return;
}

notify会导致死锁的问题

  • 多个线程调用了锁对象的wait()方法,这些线程都会进入到wait set中,等待池中的线程不参与锁竞争。此时只调用一次notify()方法,那么只有一个线程会从wait set进入到entry set竞争资源,并且获得锁资源继续执行接下来的代码。执行完毕后,释放锁。但是由于其它线程都处于等待池中,不会去竞争争夺锁,大家都在等待池中等待通知,故而造成了死锁。除非再次调用notify()或者notifyAll()去触发通知,否则会一直等待下去
  • 如果使用notifyAll则可以避免这种情况, 因为notifyAll会唤醒所有等待线程, 放入entry set中

wait / notify的开销以及问题

To be continued

相关文章:

Java 多线程 --- 线程协作 wait/notify

Java 多线程 --- 线程协作 wait/notifywait / notifyObject.wait() , Object.notify() / notifyAll()notify 和 wait 的原理notify会导致死锁的问题wait / notify的开销以及问题wait / notify 在多线程中, 如果程序拿到锁之后, 但是没有满足指定条件而不能继续往下执行, 我们可…...

【PyTorch】教程:torch.nn.Hardsigmoid

torch.nn.Hardsigmoid 原型 CLASS torch.nn.Hardsigmoid(inplaceFalse) 参数 inplace (bool) – 默认为 False 定义 Hardsigmoid(x){0if x≤−3,1if x≥3,x/61/2otherwise\text{Hardsigmoid}(x) \begin{cases} 0 & \text{if~} x \le -3, \\ 1 & \text{if~} x \ge 3…...

【手把手一起学习】(八) Altium Designer 20修改和自定义原理图标题栏

1 修改原理图标题栏 直接对原理图标题栏属性进行修改,操作如图所示: 修改后,并不会显示,故该方法不可用: 正确的操作如下,先选择合适的模板: 然后,进行属性的修改: 此时…...

业务流程测试

用例设计主要问题主要问题存在于:1、测试点分析:逻辑性不强对于整个页面功能划分不清晰;不同测试点归类不清晰;不能形成相对固定的套路,书写耗费大量时间...2、测试用例:关于,要细致到什么程度&…...

[极客大挑战 2019]EasySQL 1

[极客大挑战 2019]EasySQL 1解题POC一、解题思路之暴力破解1. 弱口令2. 暴力破解二、解题思路之万能密码1. 什么是万能密码2. 测试过程解题POC 直接点击登录获取flagflag{62f0d2ca-579e-450e-941f-5f7c23a8baf7} 一、解题思路之暴力破解 这题是万能密码,所以暴力破解…...

vulnhub raven2复现

1.扫描全网段,找出了存活主机ip为192.168.85.144 nmap 192.168.85.0/24 2.nmap扫描端口 nmap -p1-65535 192.168.85.144 3.访问此网站,没找到什么地方可以利用漏洞 ,查看中间件为wordpress 4.使用dirb对该网站进行目录扫描 dirb http://1…...

LeetCode 剑指 Offer II 079. 所有子集

给定一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 示例 1: 输入:nums [1,2,3] 输出:[[],[1],[2],[1,2],[3…...

打印名片-课后程序(Python程序开发案例教程-黑马程序员编著-第二章-课后作业)

实例3:文本进度条 进度条以动态方式实时显示计算机处理任务时的进度,它一般由已完成任务量与剩余未完成任务量的大小组成。本实例要求编写程序,实现图1所示的进度条动态显示的效果。 下载中下载完成图1文本进度条 实例分析 在本实例中可以将…...

为什么我们在判断字符串不为null后还要判断字符串长度大于0?

我们在做字符串判断时一般会: if (s ! null && s.length() > 0) {} 但是我就在想,字符串不为空了,那么他一定有值,字符串长度不就大于0吗,所以s.length()>0是不是有点多余? 我的思维误区是…...

javaEE 初阶 — 应用层中的 DNS 协议(域名解析系统)

文章目录什么是域名1. 如何建立 域名 与 IP 的对应关系2. 域名的分级什么是域名 域名也就是平常所说的网址,比如 www.baidu.com。 其实网络上的服务器要访问这个网址,需要的是 IP 地址。、 但是 IP 地址比较拗口不方便记忆,于是就有使用一些…...

【网络】-- 网络编程套接字(铺垫、预备)

目录 理解源IP地址和目的IP地址 认识端口号 端口号 理解源端口号和目的端口号 套接字 认识TCP与UDP协议 网络字节序 socket编程接口 socket 常见API sockaddr结构 理解源IP地址和目的IP地址 就如同我们唐僧的取经路: 唐僧的出发地到目的地:东…...

一文打通@SentinelResource

Sentinel 提供了 SentinelResource 注解用于定义资源&#xff0c;并提供了 AspectJ 的扩展用于自动定义资源、处理 BlockException 等 如果使用的是Sentinel Annotation AspectJ Extension&#xff0c;需要导这个依赖 <dependency><groupId>com.alibaba.csp</…...

苹果手机备份的文件在电脑什么地方 苹果备份文件怎么查看

在这个网络信息时代&#xff0c;为手机进行定期备份已经成为了家常便饭。在使用备份软件对苹果手机进行备份后&#xff0c;苹果手机备份的文件在什么地方&#xff0c;苹果备份文件怎么查看呢&#xff1f;本文就带大家来了解一下。 一、苹果手机备份的文件在电脑什么地方 大家…...

【MySQL速通篇001】5000字超详细介绍MySQL部分重要知识点

&#x1f340; 写在前面 这篇5000多字博客也花了我几天的时间&#x1f602;&#xff0c;主要是我对MySQL一部分重要知识点的理解【后面当然还会写博客补充噻&#xff0c;欢迎关注我哟】&#xff0c;当然这篇文章可能也会有不恰当的地方【毕竟也写了这么多字&#xff0c;错别字可…...

并发编程——synchronized优化原理

如果有兴趣了解更多相关内容&#xff0c;欢迎来我的个人网站看看&#xff1a;耶瞳空间 一&#xff1a;基本概念 使用synchronized实现线程同步&#xff0c;即加锁&#xff0c;实现的是悲观锁。加锁可以使一段代码在同一时间只有一个线程可以访问&#xff0c;在增加安全性的同…...

LeetCode 剑指 Offer II 083. 没有重复元素集合的全排列

给定一个不含重复数字的整数数组 nums &#xff0c;返回其 所有可能的全排列 。可以 按任意顺序 返回答案。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] 1 < nums.length < 6 -10 < nu…...

JSONObject与JSONArray使用区别

目录 1.使用的场景区别 2. 使用方法区别 3.获取方式不同 4. 解析JSON字符串 5.总结 1.使用的场景区别 想通过键值对的形式获取数据&#xff0c;使用JSONObject。如果后台查询的是某个bean的list集合向前端页面传递&#xff0c;使用JSONArray。 2. 使用方法区别 创建方法不…...

经典C程序例程:通过进程ID得到文件名

通过进程ID得到文件名 #include <stdio.h> #include <windows.h> #include <tlhelp32.h> #include <tchar.h>BOOL EnablePrivilege(HANDLE hToken,LPCSTR szPrivName); void DispProcess(void); void DispPrsFile(void);// typedef BOOL (_stdcall *E…...

【Java】Spring MVC程序开发

文章目录Spring MVC程序开发1. 什么是Spring MVC&#xff1f;1.1 MVC定义1.2 MVC 和 Spring MVC 的关系2. 为什么学习Spring MVC&#xff1f;3. 怎么学习Spring MVC&#xff1f;3.1 Spring MVC的创建和连接3.1.1 创建Spring MVC项目3.1.2 RequestMapping 注解介绍3.1.3 Request…...

leetcode题解-704. 二分查找

给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜索 nums 中的 target&#xff0c;如果目标值存在返回下标&#xff0c;否则返回 -1。 示例 1: 输入: nums [-1,0,3,5,9,12], target 9 输出: 4 解释: 9 出现…...

2.2 C语言程序的错误条件

在C语言程序中,条件语句决定程序的执行路径,因此条件表达式是程序的关键。 应用最经典的程序,除法的减法实现程序,解释条件表达式的重要性。x=y*q+r,x是被除数,y是除数,q是商,r是余数。 程序的方法, x=(r-y)+y*(1+q)。 main(){ /*错误条件的程序*/ r:=x; q:=0; whil…...

laravel 邮件发送

配置 Laravel 的邮件服务可以通过 config/mail.php 配置文件进行配置。 邮件中的每一项都在配置文件中有单独的配置项&#xff0c;甚至是独有的「传输方式」&#xff0c;允许你的应用使用不同的邮件服务发送邮件 mailers > [smtp > [transport > smtp,host > env(M…...

高性能 Jsonpath 框架,Snack3 3.2.57 发布

Snack3&#xff0c;一个高性能的 JsonPath 框架 借鉴了 Javascript 所有变量由 var 申明&#xff0c;及 Xml dom 一切都是 Node 的设计。其下一切数据都以ONode表示&#xff0c;ONode也即 One node 之意&#xff0c;代表任何类型&#xff0c;也可以转换为任何类型。 强调文档…...

Android---进程间通信机制3

1 服务如何注册到 SM 中 getIServiceManager().addService(name, service, false); getIServiceManger --- new ServiceManagerProxy(new BinderProxy()) BinderInternal.getContextObject --- 返回 BinderProxy 对象 ProcessState::self()->getContextObject: 创建一个 BpB…...

Python实战,爬取金融期货数据

大家好&#xff0c;我是毕加锁。 今天给大家带来的是 Python实战&#xff0c;爬取金融期货数据 文末送书&#xff01; 文末送书&#xff01; 文末送书&#xff01; 任务简介 首先&#xff0c;客户原需求是获取https://hq.smm.cn/copper网站上的价格数据(注&#xff1a;获取的是…...

Allegro如何导入第三方网表操作指导

Allegro如何导入第三方网表操作指导 在用Allegro做PCB设计的时候,除了支持第一方网表的导入,同样也是可以导入第三方网表的,第三方网表如下图 如何导入,具体操作如下 点击Setup点击User Preference...

高码率QPSK调制解调方案(FPGA实现篇)

在前面的章节中,已经讲过QPSK调制的方案和Matlab算法仿真,在本篇中,主要讲解基于FPGA的高速QPSK调制的实现。根据前面提到的技术指标,本系统传输的数据速率为500Mbps,中频为720MHz,因此,传统的串行QPSK调制已经不合适在FPGA中实现,需采用全数字的并行方式进行调制,具体…...

Elasticsearch的RESTful Api使用

Elasticsearch的RESTful Api使用 文章目录Elasticsearch的RESTful Api使用查询集群健康情况查看所有索引其他的_cat命令创建索引删除索引修改索引查看索引创建文档批量操作文档删除文档查询文档全量更新文档局部更新文档索引的搜索分词分析分数说明查询类型分析查询集群健康情况…...

软著申请需要注意的

一、文档格式 &#xff08;1&#xff09;程序源代码和说明文档&#xff0c;源码前后30页&#xff0c;文档前后30页。 &#xff08;2&#xff09;软件源代码和说明书的页眉必须标明软件名称、版本号和页码&#xff0c;应当与申请表中相应内容完全一致 &#xff08;3&#xff09…...

SpringBoot入门 - 添加Logback日志

SpringBoot开发中如何选用日志框架呢&#xff1f; 出于性能等原因&#xff0c;Logback 目前是springboot应用日志的标配&#xff1b; 当然有时候在生产环境中也会考虑和三方中间件采用统一处理方式。日志框架的基础在学习这块时需要一些日志框架的发展和基础&#xff0c;同时了…...