[线程]线程不安全问题 --- 内存可见性 及wait和notify

文章目录

  • 一. 由内存可见性引起线程不安全问题的例子
  • 二. 分析内存可见性产生的原因
  • 三. volatile 关键字(面试题)
  • 四. 线程的等待通知机制
    • wait
    • notify

一. 由内存可见性引起线程不安全问题的例子

public class Demo17 {private static int count = 0;public static void main(String[] args) {Thread t1 = new Thread(() -> {while(count == 0){; //循环体里啥也没有}System.out.println("t1执行结束");});Thread t2 = new Thread(() -> {Scanner scanner = new Scanner(System.in);System.out.println("请输入一个整数:");count = scanner.nextInt();});t1.start();t2.start();}
}

上述代码中, t1线程做了一个循环, 里面没有内容, 判断条件为count是否为0
t2线程, 通过输入, 修改count的值
我们预期的结果就是, 当输入一个不为0的数字时, t1线程就会结束
那么我们运行的结果:
在这里插入图片描述
发现, 线程并没有结束, 这就是bug!!
上述问题产生的原因, 就是"内存可见性"

二. 分析内存可见性产生的原因

在这里插入图片描述
这里的条件判断, 在cpu中是两条指令:

  1. load 从内存中读取数据到cpu寄存器
  2. cmp 比较, 同时会产生跳转
    如果条件成立, 继续执行
    如果条件不成立, 就跳转到另外一个地址来执行

当前循环的速度很快, 短时间内出现大量的load 和 cmp反复执行的效果
load的执行消耗的时间, 会比cmp多很多

  1. 由于上述执行过程中, load从内存读取数据的速度非常慢
    执行一次load消耗的时间, 顶上万次cmp消耗的时间
  2. 另外, JVM还发现, 每次load取到的结果是相同的(在t2修改之前)

于是, JVM干脆就把上述load操作优化掉了
只是第一次真正的进行load, 后续再执行到对应的代码, 就不在load了, 也就是不再从内存中读取数据了, 而是直接读取刚才已经load过的寄存器的值
但是优化后, 当t2对count进行修改时, t1就感知不到了

如果在while循环中加入打印操作:
在这里插入图片描述
此时就不会出现内存可见性问题
如果循环体内存在IO操作 / 阻塞操作, 这就会使循环的旋转速度大幅度降低了, 此时就没有优化的必要了

所以, 出现上述内存不可见问题, 本质上是编译器优化引起的
(编译器有且仅有javac, 但是此处优化是javac, java等配合完成工作, 但是统称为编译器)

其实, 编译器到底啥时候优化, 啥时候不优化, 也是一个"玄学问题"

三. volatile 关键字(面试题)

优化, 提高了代码的执行效率, 但是为了效率而承担bug的风险, 也是没必要的
就内存可见性问题来说, 可以通过特殊的方式来控制, 不让编译器触发优化
在这里插入图片描述
给变量修饰上这个关键字后, 此时编译器就知道了, 这个变量是"反复无常的", 就不能按照上述策略进行优化了
在这里插入图片描述
加上volatile之后, 代码执行的结果为:
在这里插入图片描述

上述问题产生的原因, 还可以从JMM(java内存模型的角度来理解)
JMM中是这么表述的:
当t1执行的时候, 要从工作内存中, 读取count值, 而不是从主内存中
后续t2修改count, 也是会修改工作内存, 同步拷贝到主内存, 但是由于t1没有重新读取主内存, 导致最终t1没有感知到t2的修改

这里说的工作内存, 不是我们平时理解的内存, 而应该翻译成"工作存储区", 应该是CPU寄存器 + 缓存
而这里的主内存, Main Memory才是我们理解的内存

四. 线程的等待通知机制

系统内部, 线程是抢占式执行, 随机调度, 程序猿其实是有办法干预的
通过"等待"的方式, 能够让线程一定程度上按照我们预期的顺序来执行
虽然我们无法主动让某个线程被调度, 但是可以主动让某个线程等待, 从而达到更精细的控制线程之间的执行顺序了

因为系统中线程调度是无序的, 很有可能会发生某个线程频繁获取释放锁, 由于获取的太快, 以至于其他线程捞不到CPU的资源, 虽然不会像死锁一样卡死, 但是可能会卡住一下, 这种现象, 叫做==“线程饿死”==

wait

等待通知机制, 就可以解决上述问题
通过条件, 判定看当前逻辑是否能够执行, 如果不能执行, 就主动wait(主动进行阻塞), 就把机会让给别的线程了, 避免该线程进行一些无意义的重试
在这里插入图片描述

  1. wait是Object类提供的方法, 任何一个对象, 都有这个方法
  2. wait 也会被Interrupt打断, wait和sleep一样, 能够自动清除标记位
  3. wait内部做的事情不仅仅是阻塞等待, 还要解锁
    准确来说, wait解锁额同事, 进行等待
    所以得先上锁, 才能谈解锁, 所以wait必须在synchronized内部使用

此时, 通过jconsole工具, 就可以看到线程的状态
在这里插入图片描述
wait还有带参数的形式, 表示最长的等待时间, 单位是毫秒, 如果超过时间还没有notify, 就自动唤醒
在这里插入图片描述

notify

通过另一线程, 调用notify来唤醒阻塞的线程, 也需要搭配锁使用
在这里插入图片描述

当t1进入wait后, 会释放locker锁, 此时t2就可以获取锁
在t2还没有输入之前, t1一直是WAITING状态
输入后, 执行notify, 就会唤醒wait操作, 是t1从阻塞状态回到了RUNNABLE状态
但是t1并不能马上被调度, 因为此时t2还没有释放锁, 意味着t1从WAITING -> RUNNABLE -> BLOCKED
等到t2释放锁以后, t1才能继续执行
执行结果:
在这里插入图片描述
注意:
如果此时t2先执行了notify, 但此时t1还没有wait
此时locker上海没有wait, 此时直接notify不会有任何效果(不会抛异常),
但是后续t1进入wait后, 没有别人唤醒了

但是, notify只能唤醒多个等待线程中的一个
在这里插入图片描述
在这里插入图片描述

上述代码, t1t2都等待解锁, t3通知后, 我们观察结果发现, 只解锁了一个进程

Object类中还有一个方法: notifyAll, 可以解锁所有等待的进程:
在这里插入图片描述
在这里插入图片描述

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

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

相关文章

linux下基本指令(持续更新)

目录 1.adduser 2.passwd 3.userdel 4. su - 5.ls 6.pwd ​编辑 7.cd 8.touch 9.mkdir 🚀 10. rmdir && rm 🚀 11.whoami (who am i) 12.clear 13.tree (需要安装 yum install -y tree) 14.who 这里我用的是腾讯…

#网络编程 笔记

认识网络 网络发展史 ARPnetA--->Internet--->移动互联网--->物联网 TCP 用来检测网络传输中差错的传输控制协议 UDP 用户数据报协议,专门负责对不同网络进行互联的互联网协议 局域网 实现小范围短距离网络通信 广域网 现大范围长距离网络通信…

Python编码系列—Python项目架构的艺术:最佳实践与实战应用

🌟🌟 欢迎来到我的技术小筑,一个专为技术探索者打造的交流空间。在这里,我们不仅分享代码的智慧,还探讨技术的深度与广度。无论您是资深开发者还是技术新手,这里都有一片属于您的天空。让我们在知识的海洋中…

(一)、软硬件全开源智能手表,与手机互联,标配多表盘,功能丰富(ZSWatch-Zephyr)

ZSWatch是一个包括硬件、软件和3D打印外壳全部开源的智能手表,软件功能丰富,并可与手机互联用来接收信息和切换歌曲,开源协议为GPL-3.0。 因为ZSWatch建立在Zephyr™项目RTOS之上,因此得名ZSWatch- Zephyr,目前该项目…

HANA5 游戏逆向

前言 某著名百合R18游戏 以前尝试逆过一次,半途而废了。今天想起来再逆一下,记录下逆向的过程。 游戏文件结构: 游戏资源extract 主要目标是弄明白游戏资源:SE、CG这些怎么加载解密的。 还是像万华镜那样下三个API断点&…

稚晖君智元机器人远程机器人系列发布:引领具身智能新高度

在最近的发布会上,前华为“天才少年”稚晖君及其团队亮相了他们的最新作品——智元机器人的第二代远程机器人系列。这次发布会不仅展示了丰富的产品线,还揭示了其未来的发展路线以及开源计划。本文将详细解析本次发布会的亮点和技术背后的创新。 一、发…

Django国际化和本地化

【图书介绍】《Django 5企业级Web应用开发实战(视频教学版)》_django 5企业级web应用开发实战(视频教学版)-CSDN博客 《Django 5企业级Web应用开发实战(视频教学版)》(王金柱)【摘要 书评 试读】- 京东图书 (jd.com) 本节主要介…

【Go函数详解】二、参数传递、变长参数与多返回值

文章目录 一、传递参数1. 按值传参2. 引用传参2.1 特殊情况2.1.1 切片slice2.1.2 字典map 二、变长参数1. 基本定义和传值1.1 基本定义1.2 传值1.2.1 普通传值1.2.2 传递切片 2. 任意类型的变长参数(泛型) 三、多返回值1. 命名返回值 一、传递参数 1. 按…

customRef 与 ref

ref() 我们已经很熟悉了,就是用来定义响应式数据的,其底层原理还是通过 Object.defineprotpty 中的 get 实现收集依赖( trackRefValue 函数收集),通过 set 实现分发依赖通知更新( triggerRefValue 函数分发 )。我们看看 ref 的源码就知道了 …

微气象在线监测系统:宏观层面的电网灾害预防和应急管理

微气象受局部地形(如山谷、河谷)、地物(如建筑物、森林)和地面条件(如水面、农田)的影响较大,而大范围气象环境则更多地受气候系统和天气模式的控制。输电线路微气象监测的主要目的是为了评估和…

YOLOv8环境搭建、创建数据集、训练推理教程(超级详细)

yolov8和yolov10 是一个流派,和yolov5区别还挺大,所以尝试使用yolov8来进行模型训练,下面是详细使用流程: 一、环境搭建 1.1 Anaconda安装 Anaconda是一个强大的开源数据科学平台,它将很多好的工具整合在一起,极大地…

华为海思招聘-芯片与器件设计工程师-数字芯片方向- 机试题——(共九套)(每套四十题)

华为海思招聘-芯片与器件设计工程师-数字芯片方向- 机试题-题目分享——共九套(每套四十题) 岗位——芯片与器件设计工程师 岗位意向——数字芯片 真题题目分享,完整版带答案(有答案和解析,答案非官方,未仔细校正&am…

论文阅读:VideoMamba: State Space Model for Efficient Video Understanding

论文地址:arxiv 摘要 为了解决视频理解中的局部冗余与全局依赖性的双重挑战。作者将 Mamba 模型应用于视频领域。所提出的 VideoMamba 克服了现有的 3D 卷积神经网络与视频 Transformer 的局限性。 经过广泛的评估提示了 VideoMamba 的能力: 在视觉领…

Hbuilder创建的项目(uniApp + Vue3)中引入UnoCSS原子css引擎

这里是UnoCSS的官网介绍 UnoCS通过简化和优化CSS的编写过程来提高Web开发的效率和可维护性。好处是: 提升开发效率提升开发效率提高一致性增强灵活性易于维护方便的集成与配置 同时还支持预设变量和规则。这些可参看官网进行配置。Unocss通过其原子化方法、高度的…

第二证券:静态市盈率与动态市盈率有什么区别?

市盈率(PE),是指投资者愿意为每一元净利润所支付的价格。 股票的市盈率股票价格(P)/每股净利润(EPS),或者用公司其时总市值/公司上一年总净利润。 动态市盈率与静态市盈率的区别&a…

<数据集>遥感航拍飞机和船舶和识别数据集<目标检测>

数据集格式:VOCYOLO格式 图片数量:19973张 标注数量(xml文件个数):19973 标注数量(txt文件个数):19973 标注类别数:2 标注类别名称:[ship,plane] 序号类别名称图片数框数1ship17575416292plane239815…

对比 PDAF、CDAF 和 LAAF 自动对焦技术

深入解析相位检测自动对焦(PDAF) 相位检测自动对焦(PDAF,Phase Detection Auto Focus)是一种高效的自动对焦技术,广泛应用于现代数码相机、无反相机和智能手机摄像头中。为了更好地理解 PDAF,我…

基于协同过滤算法的电影推荐系统的设计与实现(论文+源码)_kaic

摘 要 现在观看电影已逐渐成为人们日常生活中最常见的一种娱乐方式,人们通常会在周末或在休息、吃饭时间不由自主地在各种视频软件中搜索当前火热的影视节目。但是现在的视频软件电影推荐功能不够完善,所以需要开发出一套系统来使用户只需要简单操作就能…

华为云征文|部署私有云和文档管理系统 Kodcloud

华为云征文|部署私有云和文档管理系统 Kodcloud 一、Flexus云服务器X实例介绍1.1 云服务器介绍1.2 应用场景1.3 对比普通ECS 二、Flexus云服务器X实例配置2.1 重置密码2.2 服务器连接2.3 安全组配置 三、部署 Kodcloud3.1 Jellyfin 介绍3.2 Docker 环境搭建3.3 Jell…

【智能算法改进】路径规划问题的多策略改进樽海鞘群算法研究

目录 1.算法原理2.改进点3.结果展示4.参考文献5.代码获取 1.算法原理 【智能算法】樽海鞘群算法(SSA)原理及实现 2.改进点 无标度网络策略 复杂网络在图论中可以用边和节点表示, Barabasi 等于1999年通过分析大量的数据提出了无标度网络模型. 该网络…