java八股文面试[多线程]——虚假唤醒

阻塞队列中,如果需要线程挂起操作,判断有无数据的位置采用的是while循环 ,为什么不能换成if

肯定是不能换成if逻辑判断

线程A,线程B,线程E,线程C。 其中ABE生产者,C属于消费者

put阻塞代码:

//put方法,阻塞时可中断public void put(E e) throws InterruptedException {checkNotNull(e);final ReentrantLock lock = this.lock;lock.lockInterruptibly();//该方法可中断try {//当队列元素个数与数组长度相等时,无法添加元素while (count == items.length)//将当前调用线程挂起,添加到notFull条件队列中等待唤醒notFull.await();enqueue(e);//如果队列没有满直接添加。。} finally {lock.unlock();}}

假如线程的队列是满的,会进行阻塞,待加入的元素还未执行,需要等一个空位置

// E,拿到锁资源,还没有走while判断
while (count == items.length)// A醒了// B挂起notFull.await();
enqueue(e);

C此时消费一条数据,执行notFull.signal()唤醒一个线程A线程被唤醒(A是因为等待空位置进行的阻塞)

E这时刚好需要生产一个对象,走判断,发现有空余位置(A还没有加入元素),可以添加数据到队列,E添加数据,走enqueue,这个时候队列满了。如果判断是if(notFull.await 只执行一次)A在E释放锁资源后,拿到锁资源,直接走enqueue方法。此时A线程就是在putIndex的位置,覆盖掉之前E加入的的数据,造成数据安全问题

本质原因是,在生产者从被阻塞唤醒时,其他生产者可以能已经加了一个元素,导致队列满了。

直接看while和if的区别

可以看出来,if 是true情况下,if内的代码也只会执行一次,而while直至不满足条件才能跳出while循环

先分析while情况下
public class Demo {public static void main(String[] args) {Products data = new Products();new Thread(() -> {for (int i = 0; i < 10; i++) {data.increment();}},"A1").start();new Thread(() -> {for (int i = 0; i < 10; i++) {data.decrement();}},"B1").start();new Thread(() -> {for (int i = 0; i < 10; i++) {data.increment();}},"A2").start();new Thread(() -> {for (int i = 0; i < 10; i++) {data.decrement();}},"B2").start();}
}class Products{private int number = 0;public synchronized void increment(){while (number !=0){try {System.out.println(Thread.currentThread().getName()+"商品充足,当前商品数量为"+number);System.out.println(Thread.currentThread().getName()+"wait前");this.wait();System.out.println(Thread.currentThread().getName()+"wait后");} catch (InterruptedException e) {e.printStackTrace();}}number++;System.out.println(Thread.currentThread().getName()+"数据加一 !===>" + number);this.notifyAll();}public synchronized void decrement(){while (number == 0){try {System.out.println(Thread.currentThread().getName()+"商品不足,当前商品数量为"+number);System.out.println(Thread.currentThread().getName()+"wait前");this.wait();System.out.println(Thread.currentThread().getName()+"wait后");} catch (InterruptedException e) {e.printStackTrace();}}number--;System.out.println(Thread.currentThread().getName()+"数据减一 !===>" + number);this.notifyAll();}
}

创建了两个生产者和两个消费者

可以看出来,当前线程wait后,之后就会唤醒其他线程,获取到CPU的线程后再执行wait后面一行代码,可以得出结论 wait后 该线程代码停留在此点,并释放锁,等待唤醒后就会继续执行wait后的代码 (wait是立马释放当前锁,进入阻塞状态,notify是执行完当前代码块后面的代码再释放锁)

由此可以根据if和while的特性推导

​如果是while,唤醒后,把wait后面循环体代码执行完后,会判断while是否为true,只有不满足才能跳出while

​如果是if,唤醒后,会直接顺着wait后面的代码执行下去,不会考虑if是否为true

虚假唤醒:当线程从条件变量中苏醒过来时,发现等待的条件并没有满足,该Demo产生的情况是使用if,生产者A1执行完后,唤醒其他线程,获取到的CPU却是生产者A2,A2进入if中后,并没有满足条件,但是由于是if,会顺着执行再次生产一个,消费者同理。
 

知识来源:

虚假唤醒分析_落月飞雪的博客-CSDN博客

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

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

相关文章

FPGA时序分析与约束(4)——时序分析,时序约束,时序收敛

一、前言 在之前的文章中&#xff0c;我们介绍了组合电路的时序和时序电路的时序问题&#xff0c;之后又把理想化的时钟变成了实际的时钟考虑了进来&#xff0c;在阅读本文之前&#xff0c;强烈推荐优先阅读本系列之前的文章&#xff0c;毕竟这是我们继续学习的基础&#xff0c…

机器学习策略——优化深度学习系统

正交化&#xff08;Orthogonalization&#xff09; 老式电视机&#xff0c;有很多旋钮可以用来调整图像的各种性质&#xff0c;对于这些旧式电视&#xff0c;可能有一个旋钮用来调图像垂直方向的高度&#xff0c;另外有一个旋钮用来调图像宽度&#xff0c;也许还有一个旋钮用来…

Ansible学习笔记4

file模块&#xff1a; file模块用于对文件相关的操作&#xff08;创建、删除、属性修改、软链接等&#xff09;touch是创建。 [rootlocalhost ~]# ansible group1 -m file -a "path/tmp/111 statetouch" 192.168.17.105 | CHANGED > {"ansible_facts"…

API管理风险:如何确保您的API安全与可靠?

API管理风险&#xff1a;如何确保您的API安全与可靠&#xff1f; 随着数字化时代的到来&#xff0c;应用程序接口&#xff08;API&#xff09;在现代软件开发中发挥着关键的作用。然而&#xff0c;API管理过程中存在着各种潜在的风险。本文将探讨如何有效地管理和缓解这些风险…

linux安装firefox

1.下载对应包 https://www.mozilla.org/en-US/firefox/all/#product-desktop-release 2. 挂载桌面链接(如果/usr/bin/firefox下有的话,先删除) ln -s /opt/firefox/firefox /usr/bin/firefox 3.执行以下命令&#xff0c;即可启动Firefox客户端&#xff1a; firefox

easyexcel poi根据模板导出Excel

1.导入依赖 <!-- poi依赖--> <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>4.0.1</version> </dependency> <!-- poi对于excel 2007的支持依赖--> <dependency…

大数据项目实战(Sqoop安装)

一&#xff0c;搭建大数据集群环境 1.4 Sqoop安装 1.sqoop安装 &#xff08;1&#xff09;上传安装包 &#xff08;2&#xff09;解压安装包 tar -zxvf sqoop-1.4.6.bin__hadoop-2.0.4-alpha.tar.gz -C /export/servers &#xff08;3&#xff09;重命名 mv sqoop-1.4.6.b…

安装kali虚拟机镜像的坑

1.0 安装虚拟机镜像成功之后&#xff0c;只有光标&#xff0c;没有界面 在VMware上安装kali linux环境时&#xff0c;根据提示操作完成后&#xff0c;开启虚拟机&#xff0c;屏幕黑屏&#xff0c;左上角有一个光标在闪&#xff0c;一直开不了机。 出现问题的原因&#xff0c;…

拓世科技集团 | “书剑人生”李步云学术思想研讨会暨李步云先生九十华诞志庆

2023年&#xff0c;中国改革开放迎来了45周年&#xff0c;改革春风浩荡&#xff0c;席卷神州大地&#xff0c;45年间&#xff0c;中国特色社会主义伟大事业大步迈入崭新境界&#xff0c;一路上结出了饶为丰硕的果实。中华民族在这45年间的砥砺前行&#xff0c;不仅使中国的经济…

ELK安装、部署、调试 (二) ES的安装部署

ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎&#xff0c;基于RESTful web接口操作ES&#xff0c;也可以利用Java API。Elasticsearch是用Java开发的&#xff0c;并作为Apache许可条款下的开放源码发布&#xff0c;是当前流行的企业…

漂浮岛场景WebGL效果解析

访问在线地址&#xff0c;代码在此处。 场景构图 该场景使用了3个岩石模型&#xff0c;一些通用的阙类植物、树木模型&#xff0c;还有空中的鸟类模型。 场景的渲染顺序&#xff1a;深度预通道&#xff0c;岩石&#xff0c;鸟类&#xff0c;天空&#xff0c;云粒子。 相机…

yolov5模型转换

yolov5本身release目录有提供了onnx转换好的模型&#xff0c;想着也自己操作一遍&#xff0c;可是实际操作却遇到了问题&#xff0c;这里做下记录方便后续可能用到 安装onnx&#xff0c;转的时候提示出错ONNX: export failure 0.1s: Unsupported ONNX opset version: 17 修改…