详解 Java多线程带来的的风险-线程安全

目录

一、什么是线程安全?

 二、线程不安全的原因

1、线程调度是随机的

2、修改共享数据:多个线程修改同⼀个变量

3、原⼦性  ​编辑

(1)什么是原⼦性

(2)⼀条 java 语句不⼀定是原⼦的,也不⼀定只是⼀条指令 

(3)不保证原⼦性会给多线程带来什么问题

(4)可⻅性:可⻅性指, ⼀个线程对共享变量值的修改,能够及时地被其他线程看到.

(5)Java 内存模型 (JMM) 

 1) 初始情况下, 两个线程的⼯作内存内容⼀致.

​编辑 2) ⼀旦线程1 修改了 a 的值, 此时主内存不⼀定能及时同步. 对应的线程2 的⼯作内存的 a 的值也不⼀定能及时同步.

此时引⼊了两个问题:

1) 为啥整这么多内存?

2) 为啥要这么⿇烦的拷来拷去?

4、指令重排序


引言:

        在 Java 编程中,线程安全是一个至关重要的概念。当多个线程同时访问共享的资源时,如果没有适当的同步措施,就会出现数据竞争和不一致的情况,从而导致程序出现各种难以预料的错误。因此,理解并处理线程安全问题是编写高质量、可靠性强的 Java 程序的关键。

一、什么是线程安全?

        线程安全是指在多线程环境中,对共享资源的访问不会导致数据的损坏或不一致。一个线程安全的程序在多线程环境下执行时,能够确保各个线程都能正确地操作共享的数据,而不会产生意外结果。

 二、线程不安全的原因

1、线程调度是随机的

这是线程安全问题的 罪魁祸⾸
随机调度使⼀个程序在多线程环境下, 执⾏顺序存在很多的变数.
程序猿必须保证 在任意执⾏顺序下 , 代码都能正常⼯作.

2、修改共享数据:多个线程修改同⼀个变量

3、原⼦性  

(1)什么是原⼦性
我们把⼀段代码想象成⼀个房间,每个线程就是要进⼊这个房间的⼈。如果没有任何机制保证,A进⼊ 房间之后,还没有出来;B 是不是也可以进⼊房间,打断 A 在房间⾥的隐私。这个就是不具备原⼦性 的。
那我们应该如何解决这个问题呢?是不是只要给房间加⼀把锁,A 进去就把⻔锁上,其他⼈是不是就进不来了。这样就保证了这段代码的原⼦性了。
有时也把这个现象叫做同步互斥,表⽰操作是互相排斥的。
(2)⼀条 java 语句不⼀定是原⼦的,也不⼀定只是⼀条指令 
⽐如刚才我们看到的 n++,其实是由三步操作组成的:
  1. 从内存把数据读到 CPU
  2. 进⾏数据更新
  3. 把数据写回到 CPU
(3)不保证原⼦性会给多线程带来什么问题
如果⼀个线程正在对⼀个变量操作,中途其他线程插⼊进来了,如果这个操作被打断了,结果就可能是错误的。 这点也和线程的抢占式调度密切相关. 如果线程不是 "抢占" 的, 就算没有原⼦性, 也问题不⼤.
(4)可⻅性:可⻅性指, ⼀个线程对共享变量值的修改,能够及时地被其他线程看到.
(5)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的⽅式执⾏,也是没问题,可以少跑⼀次前台。这种叫做指令重排序

 编译器对于指令重排序的前提是 "保持逻辑不发⽣变化". 这⼀点在单线程环境下⽐较容易判断, 但是在多线程环境下就没那么容易了, 多线程的代码执⾏复杂程度更⾼, 编译器很难在编译阶段对代码的执⾏效果进⾏预测, 因此激进的重排序很容易导致优化后的逻辑和之前不等价.

 总结:

        在编写 Java 程序时,必须时刻牢记线程安全问题,合理使用同步机制、并发容器和原子类等工具,确保多线程环境下程序的正确性和稳定性。只有这样,才能编写出高效、健壮的多线程应用。

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

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

相关文章

文心一言指令词宝典之求职招聘篇

作者:哈哥撩编程(视频号、抖音、公众号同名) 新星计划全栈领域优秀创作者博客专家全国博客之星第四名超级个体COC上海社区主理人特约讲师谷歌亚马逊演讲嘉宾科技博主极星会首批签约作者 🏆 推荐专栏: 🏅…

C语言函数递归调用

在C语言中,函数可以直接或间接地调用自身,这种函数调用自身的过程称为递归调用。递归是一种强大的编程技巧,能够简化程序结构、提高代码的可读性和可维护性。本文将介绍C语言函数递归调用的原理、应用场景以及注意事项。 以下是我整理的关于…

PinkysPalaceV2靶场详解IDA逆向查看缓存区溢出漏洞原理以及使用kali gdb使用超详细三次提权字典生成

下载链接: Pinkys Palace: v2 ~ VulnHub 安装: 正常用vm虚拟机打开即可,注意导入时所选择的硬盘存储目录应为空目录,否则会导入失败 根据下载链接提示我们需要更改host文件,以便于我们可以正常访问 kali中的host文件位置为 /etc/h…

弧形导轨在自动化设备中的传动原理

在自动化机械系统中,弧形导轨是一种常见的轨道结构,用于支撑和引导物体沿着指定的弧线运动。其工作原理基于几何学和物理学的原理。 弧形导轨通常由一个弧形的轨道和一个移动部件组成。轨道一般呈弧形,其几何形状可以是圆弧、椭圆弧等&#x…

智慧工地整体解决方案(3)

塔吊安全管理系统 需求分析 塔式起重机是现代施工中必不可少的关键设备,是施工企业装备水平的标志性重要装备之一。随着近年来建筑行业塔机的大量使用,由于塔机违规超限作业和塔机群干涉碰撞等引发的各类塔机运行安全事故频繁发生,造成了巨大的生命财产损失。 典型事故现…

Linux 设备树: 设备树节点与属性在 dtb 文件中的存储

前言 当前新版本的 Linux 内核 设备驱动框架,与设备树(Device Tree)结合密切,整体 设备树的设备驱动框架,比较的庞大,但又非常的经典。 一个个的 设备树解析函数,都是前人【智慧】的结晶&#…

【pysurvival Python 安装失败】

这个错误与 sklearn 包的名称更改有关,导致 pysurvival 在构建元数据时失败。现在,你需要修改 pysurvival 的安装文件以使用正确的 scikit-learn 包名 编辑安装文件:找到 pysurvival 的安装文件,可能是 setup.py 或 pyproject.to…

智慧公厕:改变城市生活的革命性基础设施

在现代城市的高品质生活要求背景下,公共厕所成为了不可或缺的基础设施。然而,传统的公厕在服务质量、管理效率方面存在一定的问题。为了提供更好的公厕服务,智慧公厕应运而生。通过智能化的管理模式,智慧公厕实现了公厕使用与管理…

玩转ChatGPT:Suno制作音乐

AI开始进军音乐领域了。 一款音乐AI神器——Suno V3发布,它能够处理从间奏到主歌、副歌、桥段直至尾奏的完整结构,零门槛创作音乐。 需要科学上网,官方网站:https://app.suno.ai/ 使用GPT写个歌词,然后丢进Suno生成…

Web APIs知识点讲解(阶段七)

正则表达式 1.能够利用正则表达式校验输入信息的合法性2. 具备利用正则表达式验证小兔鲜注册页面表单的能力 一.正则表达式 1.正则表达式 正则表达式(Regular Expression)是用于匹配字符串中字符组合的模式。在 JavaScript中,正则表达式也…

光明源@智慧厕所公厕软件系统有哪些核心功能?

在现代城市的建设中,智慧公厕的建设成为了提升城市品质和居民生活质量的重要举措。而智慧公厕的核心,不仅仅在于其硬件设备的智能化,同样重要的是其背后支持的智慧厕所公厕软件系统。让我们一起探讨,智慧厕所公厕软件系统有哪些核…

【C++】开散列实现unordered_map与unordered_set的封装

> 作者:დ旧言~ > 座右铭:松树千年终是朽,槿花一日自为荣。 > 目标:手撕哈希表的闭散列和开散列 > 毒鸡汤:谁不是一边受伤,一边学会坚强。 > 专栏选自:C嘎嘎进阶 > 望小伙伴们…

c语言例题,实现一个整型有序数组的二分查找

c语言中,有很多可以实现效果的方法,而在一个整型有序的数组中,我们可以使用二分查找的方法来实现对于一个数组中的元素查找。二分查找的优点在于本身需要的计算是比较少的,一次计算查找排除掉数组中一半的元素,尤其对于…

Topaz Photo AI for Mac v2.4.2 智能AI降噪软件

Topaz Photo AI是一款适用于Mac的图像处理软件,使用人工智能技术对照片进行编辑和优化。该软件提供了多种强大的功能,包括降噪、锐化、消除噪点、提高分辨率等,可以帮助用户改善图像质量,并实现自定义的效果。 软件下载&#xff1…

探究贪心算法:特点与实际应用

探究贪心算法:特点与实际应用 探究贪心算法:特点与实际应用📝 摘要🚀 引言📋 正文内容(详细介绍)📌 小结📊 表格总结🎯 总结🔮 未来展望&#x1f…

C#.net8创建webapi,使用SqlSugar,仓储模式,DTO,服务层,控制层的综合应用(企业级)

本文源码地址: https://download.csdn.net/download/u012563853/89036104 源码中,也有详细的注释说明。 代码总览: 这是一个综合性比较强的文章,需要有一定的基础,没有基础的人,看了后,会全面的了解一下,有基础的人,看了后会加强认识,更加的巩固,直接在项目中去应…

详解 Java 中的 volatile 关键字

引言: 在 Java 编程中,volatile 是一个非常重要的关键字,用于修饰变量。它主要用于确保多个线程之间对共享变量的修改能够被及时地更新到主内存,并且能够保证可见性。然而,需要注意的是,volatile 关键字并不…

PS之更换背景色

1.更换背景色 导入图片后, 选中快速选择工具, 依次点击 选择主体 -> 选择并遮住 其后右边会出现一栏 “属性”, 拉到最下面的 “输出设置”, 选择净化颜色, 然后确认 此时应该得到抠出来的物体. 右下角点击新建图层 此时对图层2打开拾色器, 将图层2 设为白色 然后CTRL…

二维码门楼牌管理应用平台:创新管理与服务的全新方式

文章目录 前言一、二维码门楼牌管理应用平台的建设背景二、二维码门楼牌管理应用平台的功能特点三、切换功能在城市管理中的应用四、二维码门楼牌管理应用平台的未来展望 前言 在数字化时代的浪潮中,二维码技术以其便捷、高效的特点,正逐渐渗透到我们生…

ArrayList和LinkedList的区别【大白话Java面试题】

ArrayList和LinkedList的区别【大白话Java面试题】 大白话回答 arraylist和linkedlist的区别是:数据结构不同,效率不同,自由性不同,主要控件开销不同 数据结构不同 ArrayList是Array(动态数组)的数据结构,LinkedList…