【JavaEE面试题(九)线程安全问题的原因和解决方案】

多线程-初阶

  • 4. 多线程带来的的风险-线程安全 (重点)
    • 4.1 观察线程不安全
            • 原因是 1.load 2. add 3. save
    • 4.2 线程安全的概念
    • 4.3 线程不安全的原因
            • 最根本的是 操作系统对线程的调度是随机的
            • ★1. 修改共享数据(多个线程修改同一个变量)
            • ★2. 操作不是原子性
            • ★3. 可见性
            • ★4. 代码顺序性
    • 4.4 解决之前的线程不安全问题

4. 多线程带来的的风险-线程安全 (重点)

4.1 观察线程不安全

static class Counter {public int count = 0;void increase() {count++;}
}
public static void main(String[] args) throws InterruptedException {final Counter counter = new Counter();Thread t1 = new Thread(() -> {for (int i = 0; i < 50000; i++) {counter.increase();}});Thread t2 = new Thread(() -> {for (int i = 0; i < 50000; i++) {counter.increase();}});t1.start();t2.start();t1.join();t2.join();System.out.println(counter.count);
}

大家观察下是否适用多线程的现象是否一致?同时尝试思考下为什么会有这样的现象发生呢?

原因是 1.load 2. add 3. save

在这里插入图片描述

注意:可能会导致 小于5w

4.2 线程安全的概念

想给出一个线程安全的确切定义是复杂的,但我们可以这样认为:
如果多线程环境下代码运行的结果是符合我们预期的,即在单线程环境应该的结果,则说这个程序是线程安全的

4.3 线程不安全的原因

在这里插入图片描述

最根本的是 操作系统对线程的调度是随机的
★1. 修改共享数据(多个线程修改同一个变量)

上面的线程不安全的代码中, 涉及到多个线程针对 counter.count 变量进行修改.
此时这个 counter.count 是一个多个线程都能访问到的 “共享数据”
counter.count 这个变量就是在堆上. 因此可以被多个线程共享访问

★2. 操作不是原子性

在这里插入图片描述

在这里插入图片描述
什么是原子性

我们把一段代码想象成一个房间,每个线程就是要进入这个房间的人。如果没有任何机制保证,A进入房间之后,还没有出来;B 是不是也可以进入房间,打断 A 在房间里的隐私。这个就是不具备原子性的。
那我们应该如何解决这个问题呢?是不是只要给房间加一把锁,A 进去就把门锁上,其他人是不是就进不来了。这样就保证了这段代码的原子性了。
有时也把这个现象叫做同步互斥,表示操作是互相排斥的

一条 java 语句不一定是原子的,也不一定只是一条指令

比如刚才我们看到的 n++,其实是由三步操作组成的:

  1. 从内存把数据读到 CPU
  2. 进行数据更新
  3. 把数据写回到 CPU

不保证原子性会给多线程带来什么问题

如果一个线程正在对一个变量操作,中途其他线程插入进来了,如果这个操作被打断了,结果就可能是错误的。
这点也和线程的抢占式调度密切相关. 如果线程不是 “抢占” 的, 就算没有原子性, 也问题不大.

★3. 可见性

可见性指, 一个线程对共享变量值的修改,能够及时地被其他线程看到

Java 内存模型 (JMM): Java虚拟机规范中定义了Java内存模型.
目的是屏蔽掉各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到一致的并发效果.

在这里插入图片描述

  • 线程之间的共享变量存在 主内存 (Main Memory).
  • 每一个线程都有自己的 “工作内存” (Working Memory) .
  • 当线程要读取一个共享变量的时候, 会先把变量从主内存拷贝到工作内存, 再从工作内存读取数据.
  • 当线程要修改一个共享变量的时候, 也会先修改工作内存中的副本, 再同步回主内存

由于每个线程有自己的工作内存, 这些工作内存中的内容相当于同一个共享变量的 “副本”. 此时修改线程1 的工作内存中的值, 线程2 的工作内存不一定会及时变化

  1. 初始情况下, 两个线程的工作内存内容一致在这里插入图片描述
  2. 一旦线程1 修改了 a 的值, 此时主内存不一定能及时同步. 对应的线程2 的工作内存的 a 的值也不一定能及时同步.在这里插入图片描述
    这个时候代码中就容易出现问题

此时引入了两个问题:

  • 为啥要整这么多内存?
  • 为啥要这么麻烦的拷来拷去?
  1. 为啥整这么多内存?
    实际并没有这么多 “内存”. 这只是 Java 规范中的一个术语, 是属于 “抽象” 的叫法.
    所谓的 “主内存” 才是真正硬件角度的 “内存”. 而所谓的 “工作内存”, 则是指 CPU 的寄存器和高速缓存.
  2. 为啥要这么麻烦的拷来拷去?
    因为 CPU 访问自身寄存器的速度以及高速缓存的速度, 远远超过访问内存的速度(快了 3 - 4 个数量级, 也就是几千倍, 上万倍)

比如某个代码中要连续 10 次读取某个变量的值, 如果 10 次都从内存读, 速度是很慢的. 但是如果
只是第一次从内存读, 读到的结果缓存到 CPU 的某个寄存器中, 那么后 9 次读数据就不必直接访问
内存了. 效率就大大提高了

那么接下来问题又来了, 既然访问寄存器速度这么快, 还要内存干啥??
答案就是一个字: 贵

值的一提的是, 快和慢都是相对的. CPU 访问寄存器速度远远快于内存, 但是内存的访问速度又远远快于硬盘.
对应的, CPU 的价格最贵, 内存次之, 硬盘最便宜

★4. 代码顺序性

什么是代码重排序

一段代码是这样的:

  1. 去前台取下 U 盘
  2. 去教室写 10 分钟作业
  3. 去前台取下快递

如果是在单线程情况下,JVM、CPU指令集会对其进行优化,比如,按 1->3->2的方式执行,也是没问题,可以少跑一次前台。这种叫做指令重排序
编译器对于指令重排序的前提是 “保持逻辑不发生变化”. 这一点在单线程环境下比较容易判断, 但是在多线程环境下就没那么容易了, 多线程的代码执行复杂程度更高, 编译器很难在编译阶段对代码的执行效果进行预测, 因此激进的重排序很容易导致优化后的逻辑和之前不等价

重排序是一个比较复杂的话题, 涉及到 CPU 以及编译器的一些底层工作原理, 此处不做过多讨论

4.4 解决之前的线程不安全问题

这里用到的机制,我们马上会给大家解释

static class Counter {public int count = 0;synchronized void increase() {count++;}
}
public static void main(String[] args) throws InterruptedException {final Counter counter = new Counter();Thread t1 = new Thread(() -> {for (int i = 0; i < 50000; i++) {counter.increase();}});Thread t2 = new Thread(() -> {for (int i = 0; i < 50000; i++) {counter.increase();}});t1.start();t2.start();t1.join();t2.join();System.out.println(counter.count);
}

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

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

相关文章

园区水电能源管理系统平台

园区水电能源管理系统平台是一种集成了水电能源监测、管理和优化功能的平台&#xff0c;旨在帮助园区管理者实现对水电资源的实时监测、合理节能和优化使用。随着能源需求的不断增长和能源价格的不断攀升&#xff0c;园区管理者面临着越来越大的节能减排压力。因此&#xff0c;…

IDEA中设置鼠标滚轮修改字体大小

IDEA中设置鼠标滚轮修改字体大小&#xff1f; 选择File--Settings--Editor--General&#xff0c;把 Mouse Control 前的对勾勾选 后点击 OK 即可。 勾选此设置后&#xff0c;增加 Ctrl 鼠标滚轮 快捷键来控制代码字体大小显 示。字体随时可以放大缩小~~可真好用呢~

OpenCv之图像轮廓

目录 一、图像轮廓定义 二、绘制轮廓 三、计算轮廓面积与周长 一、图像轮廓定义 图像轮廓是具有相同颜色或灰度的连续带你的曲线.轮廓在形状分析和物体的检测和识别中很有用 轮廓的作用: 用于图形分析物体的识别与检测 注意点: 为了检测的准确性&#xff0c;需要先对图像…

什么是 XSS 攻击,攻击原理是什么

什么是 XSS 攻击&#xff1f; XSS&#xff08;Cross-Site Scripting&#xff09;攻击是一种常见的 Web 安全漏洞&#xff0c;其攻击目标是 Web 应用程序中的用户&#xff0c;攻击者通过在 Web 页面中植入恶意脚本&#xff0c;从而实现窃取用户敏感信息、篡改用户数据等目的。 …

线程与信号

1. 进程内所有线程共享信号处理配置&#xff0c;故信号配置可以全部放在主线程内。 2. 每个线程有自己的信号掩码sigset_t&#xff0c;线程创建时继承创建时线程的信号掩码。 3. 触发信号处理函数按创建线程顺序分配给当前空闲线程&#xff0c;信号处理函数内是可以阻塞的。 …

云计算名词-IaaS,PaaS,SaaS

在学习分布式的过程中&#xff0c;知道了PaaS这个词儿&#xff0c;但是不知道是什么意思。从网上查询了之后&#xff0c;做了简单的了解。这里简单记录一下&#xff0c;方面之后的查阅。 IAAS&#xff08;Infrastructure-as-a-Service&#xff09;基础设施即服务 网上的定义是…

webpack相关

在 webpack < 4 的版本中&#xff0c;通常将 vendor 作为一个单独的入口起点添加到 entry 选项中&#xff0c;以将其编译为一个单独的文件&#xff08;与 CommonsChunkPlugin 结合使用&#xff09;。而在 webpack 4 中不鼓励这样做。而是使用 optimization.splitChunks 选项…

【MySQL】MySQL数据库的初阶使用

文章目录 一、MySQL服务的安装二、数据库基础1.什么是数据库&#xff1f;&#xff08;基于CS模式的一套数据存取的网络服务&#xff09;2. Linux文件系统和数据库的关系 && 主流数据库3.MySQL架构 && SQL分类 && MySQL存储引擎 三、MySQL操作库1.库结构…

ELK-日志服务【redis-配置使用】

目录 环境 【1】redis配置 【2】filebeat配置 【3】对接logstash配置 【4】验证 【5】安全配置&#xff1a;第一种&#xff1a;kibana-nginx访问控制 【6】第二种&#xff1a;在ES-主节点-配置TLS 【7】kibana配置密码 【8】logstash添加用户密码 环境 es-01,kibana 1…

掘金量化—Python SDK文档—5.API 介绍(1)

​ Python SDK文档 5.API 介绍 5.1基本函数 init - 初始化策略 初始化策略, 策略启动时自动执行。可以在这里初始化策略配置参数。 函数原型&#xff1a; init(context)参数&#xff1a; 参数名类型说明contextcontext上下文&#xff0c;全局变量可存储在这里 示例&…

数据分析之Matplotlib

文章目录 1. 认识数据可视化和Matplotlib安装2. 类型目录3. 图标名称title4. 处理图形中的中文问题5. 设置坐标轴名称&#xff0c;字体大小&#xff0c;线条粗细6. 绘制多个线条和zorder叠加顺序7. 设置x轴刻度xticks和y轴刻度yticks8. 显示图表show9. 设置图例legend10. 显示线…

vue 项目优化

去除冗余的css 消除框架中未使用的CSS,初步达到按需引入的效果 使用背景&#xff1a;vue2.x, webpack3.x 使用插件&#xff1a;purifycss-webpack 安装&#xff1a; npm i purifycss-webpack purify-css glob-all -D安装后各个插件的版本&#xff1a; “glob-all”: “^3.3.…

从小白到大神之路之学习运维第64天--------Zabbix监控mysql、ftp服务以及自定义配置

第三阶段基础 时 间&#xff1a;2023年7月19日 参加人&#xff1a;全班人员 内 容&#xff1a; Zabbix监控mysql、ftp服务以及自定义 目录 一、Zabbix监控mysql数据库 二、Zabbix监控ftp服务 三、Zabbix自定义监控项 整体zabbix搭建完成&#xff0c;server端huyang1监…

吴恩达机器学习2022-Jupyter-Scikit-Learn教学

1可选实验室: 线性回归使用 Scikit-Learn 有一个开源的、商业上可用的机器学习工具包&#xff0c;叫做 scikit-learn。本工具包包含您将在本课程中使用的许多算法的实现。 1.1目标 在这个实验室里: 利用 scikit-学习使用线性回归梯度下降法来实现 1.2工具 您将利用 sciki…

Navidrome - 开源音乐服务器【打造属于自己的音乐播放器】「端口映射」随时随地想听就听

转载自cpolar极点云文章&#xff1a;Navidrome - 开源音乐服务器【打造属于自己的音乐播放器】「端口映射」随时随地想听就听 1. 前言 不知从何时开始&#xff0c;我们能用的音乐软件越来越少&#xff0c;笔者使用小米手机很久了&#xff0c;自从小米手机的自带音乐播放器变成…

RabbitMQ到底为什么要使用它?

导入 一个技术的衍生必然是为了解决现实出现的问题&#xff0c;在讲这个问题之前我们先了解一下传统开发中关于服务调用出现的问题&#xff08;痛点&#xff09;有哪些&#xff1f; 我们为什么要使用MQ&#xff1f; ①、同步——超时 在多服务体系架构中&#xff0c;必然存在…

Kyuubi的介绍优势(官网链接)

官网链接&#xff1a;https://kyuubi.apache.org/ Apache Kyuubi™ 是一个分布式多租户网关&#xff0c;用于在数据仓库和 Lakehouse 上提供无服务器 SQL。 Kyuubi 在各种现代计算框架&#xff08;例如 Apache Spark、 Flink、 Doris、 Hive和Trino等&#xff09;之上构建分布…

全志F1C200S嵌入式驱动开发(GPIO输出)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】 和v3s一样,f1c200s本身的外部引脚比较少。所以这个时候,不可避免地,很多引脚的功能就会重叠在一起。这种情况下,我们就要学会取舍了。比如说,如果是学习sd卡的时候,那么spi的…

CSS——基础知识及使用

CSS 是什么 CSS是层叠样式表 (Cascading Style Sheets)的简写.CSS 能够对网页中元素位置的排版进行像素级精确控制, 实现美化页面的效果. 能够做到页面的样式和结构分离。 基本语法规范 选择器 { 一条/N条声明 } 选择器决定针对谁修改 (找谁)声明决定修改啥. (干啥)声明的…

css3的新特性

动画效果 过渡 transition 鼠标放上去瞬间变大 过渡是变大的过程慢慢变化 第一个参数&#xff1a;对哪些值进行过渡。all为hover中所有&#xff0c;也可以指定属性 第二个参数&#xff1a;让动画过渡多长时间。要添加单位&#xff08;s秒&#xff09; 第三个参数&#xff1…