为什么WAIT必须在同步块中
我们知道java的Object有wait和notify方法,如果要使用wait和notify的话,那么必须在synchronized块中,否则会抛出IllegalMonitorStateException。但是为什么必须在同步块中调用呢?直接wait,然后在notify不行吗?我一直存在这样的疑问,只到后来查到了Stack Overflow的一个回答,豁然开朗。大概翻译了下:
假设我们要自定义一个blocking queue,如果没有使用synchronized的话,我们可能会这样写:
class BlockingQueue {
Queue<String> buffer = new LinkedList<String>();
public void give(String data) {
buffer.add(data);
notify(); // Since someone may be waiting in take!
}
public String take() throws InterruptedException {
while (buffer.isEmpty()) // 不能用if,因为为了防止虚假唤醒
wait();
return buffer.remove();
}
}
这段代码可能会导致如下问题:
- 一个消费者调用take,发现buffer.isEmpty
- 在消费者调用wait之前,由于cpu的调度,消费者线程被挂起,生产者调用give,然后notify
- 然后消费者调用wait (注意,由于错误的条件判断,导致wait调用在notify之后,这是关键)
- 如果很不幸的话,生产者产生了一条消息后就不再生产消息了,那么消费者就会一直挂起,无法消费,造成死锁。
解决这个问题的方法就是:总是让give/notify和take/wait为原子操作。
也就是说wait/notify是线程之间的通信,他们存在竞态,我们必须保证在满足条件的情况下才进行wait。换句话说,如果不加锁的话,那么wait被调用的时候可能wait的条件已经不满足了(如上述)。由于错误的条件下进行了wait,那么就有可能永远不会被notify到,所以我们需要强制wait/notify在synchronized中
最后附上Stack Overflow的原文链接:
https://stackoverflow.com/questions/2779484/why-must-wait-always-be-in-synchronized-block
为什么WAIT必须在同步块中的更多相关文章
- Java中wait()方法为什么要放在同步块中?(lost wake-up 问题)
问题起源 事情得从一个多线程编程里面臭名昭著的问题"Lost wake-up problem"说起. 这个问题并不是说只在Java语言中会出现,而是会在所有的多线程环境下出现. 假 ...
- 阿里面试题,为什么wait()方法要放在同步块中?
某天我在***的时候,突然有个小伙伴微信上说:“哥,阿里面试又又挂了,被问到为什么wait()方法要放在同步块中,没答出来!” 我顿时觉得**一紧,仔细回顾一下,如果wait()方法不在同步块中,代码 ...
- 为什么 wait(), notify()和 notifyAll ()必须在同步方法或 者同步块中被调用?
当一个线程需要调用对象的 wait()方法的时候,这个线程必须拥有该对象的锁,接 着它就会释放这个对象锁并进入等待状态直到其他线程调用这个对象上的 notify() 方法.同样的,当一个线程需要调用对 ...
- 解释为什么wait()和notify(), notifyAll()要放在同步块中
首先,wait()是释放锁的,因此wait()之前要先获得锁,而锁在同步块开始的时候获得,结束时释放,即同步块内为持有锁的阶段. 那为什么要设计同步块呢?或者说没有同步块会怎样呢?
- 为什么 wait 和 notify 方法要在同步块中调用?
Java API 强制要求这样做,如果你不这么做,你的代码会抛出 IllegalMonitorStateException 异常.还有一个原因是为了避免 wait 和 notify 之间产生竞态条件.
- 为什么 wait()方法和 notify()/notifyAll()方法要在同步块 中被调用 ?
这是 JDK 强制的,wait()方法和 notify()/notifyAll()方法在调用前都必须先获得对 象的锁
- java 为什么wait(),notify(),notifyAll()必须在同步(Synchronized)方法/代码块中调用?
wait()作用:该方法用来将当前线程置入休眠状态,直到接到通知或被中断为止.条件:在调用wait()之前,线程必须要获得该对象的对象级别锁,即只能在同步方法或同步块中调用wait()方法.进入wai ...
- .NET中如何在同步代码块中调用异步方法
更新记录 本文迁移自Panda666原博客,原发布时间:2021年7月2日. 在同步代码块中调用异步方法,方法有很多. 一.对于有返回值的Task 在同步代码块中直接访问 Task 的 Result ...
- java多线程-同步块
Java 同步块(synchronized block)用来标记方法或者代码块是同步的.Java 同步块用来避免竞争.本文介绍以下内容: Java 同步关键字(synchronzied) 实例方法同步 ...
随机推荐
- CVE-2021-40449 NtGdiResetDC UAF
背景 CVE-2021-40449是一个存在于Win32k内核驱动中的UAF漏洞.该漏洞在2021年八月下旬九月上旬被Kaspersky发现用于野外攻击活动中.通过Hook win32k驱动执行N ...
- 浅谈bi工具的含义和不同类型
什么是BI工具? 商业智能(BI)工具是利用一组方法和技术来准备,呈现和帮助分析数据的工具.通过此过程,数据将转化为可操作的业务信息,帮助决策者和最终用户做出更有效的数据驱动决策. 商业智能使用的一 ...
- 【C#】String| StringBuilder 字符
原文链接:https://www.cnblogs.com/huameitang/p/10528646.html 字符串是用于表示文本的字符的有序集合. String对象是对象的有序集合 System. ...
- Oracle的发展历程
我们学习的是ORACLE(甲骨文)公司(就是收购Sun公司的甲骨文公司)的Oracle数据库(Oracle Database).Oracle数据库是关系型数据库中的大型数据库,存储量大,而且也非常安全 ...
- C#基于Redis实现分布式锁
[本博客属于原创,如需转载,请注明出处:https://www.cnblogs.com/gdouzz/p/12097968.html] 最近研究库存的相关,在高峰期经常出现超卖等等情况,最后根据采用是 ...
- 经验分享:分析如何使程序在Linux下后台运行---Linux就该这么学!
转至:https://www.cnblogs.com/maoju/p/13848740.html 一.为什么要使程序在后台执行 我们计算的程序都是周期很长的,通常要几个小时甚至一个星期.我们用的环 ...
- 《Selenium+Pytest Web自动化实战》随到随学在线课程,零基础也能学!
课程介绍 课程主题:<Selenium+Pytest Web自动化实战> 适合人群: 1.功能测试转型自动化测试 2.web自动化零基础的小白 3.对python 和 selenium 有 ...
- Word:在文中插入对参考文献的引用
1.工具栏→插入→交叉引用 2."交叉引用"工具栏 引用类型:编号项: 引用内容:段落编号 选中要引用的参考文献编号 3.结果
- Java:安装新版本Java、环境配置
最新版2021年版 Java安装目录 2.在系统变量中设置2项属性,JAVA_HOME.PATH(大小写无所谓),若已存在这点击编辑,不存在则新建 参数为: JAVA_HOME: D:\Java\ ...
- 利用POST请求模拟登录豆瓣
需要用requests库 豆瓣上次更新后,就不能通过直接的requests.post()方式直接传递参数登录了.必须新建session,先GET请求,然后POST才能成功.原因未知 data参数中的四 ...