线程安全、共享变量的可见性

news2024/9/27 12:08:03

Java中的线程安全问题

谈到线程安全问题,我们先说说什么是共享资源。所谓共享资源,就是说该资源被多个线程所持有或者说多个线程都可以去访问该资源。

线程安全问题是指当多个线程同时读写一个共享资源并且没有任何同步措施时,导致出现脏数据或者其他不可预见的结果的问题。

在这里插入图片描述
线程A和线程B可以同时操作主内存中的共享变量,那么线程安全问题和共享资源之间是什么关系呢?

是不是说多个线程共享了资源,当它们都去访问这个共享资源时就会产生线程安全问题呢?答案是否定的,如果多个线程都只是读取共享资源,而不去修改,那么就不会存在线程安全问题,只有当至少一个线程修改共享资源时才会存在线程安全问题。

最典型的就是计数器类的实现,计数变量count本身是一个共享变量,多个线程可以对其进行递增操作,如果不使用同步措施,由于递增操作是获取一计算一保存三步操作,因此可能导致计数不准确。

在这里插入图片描述
假如当前count=0,在t1时刻线程A读取count值到本地变量countA。

然后在t2时刻递增countA的值为1,同时线程B读取count的值0到本地变量countB,此时countB的值为0(因为countA的值还没有被写入主内存)。

在t3时刻线程A才把countA的值1写入主内存,至此线程A一次计数完毕,同时线程B递增CountB的值为1。

在t4时刻线程B把countB的值1写入内存,至此线程B一次计数完毕。

这里先不考虑内存可见性问题,明明是两次计数,为何最后结果是1而不是2呢?其实这就是共享变量的线程安全问题。

那么如何来解决这个问题呢?这就需要在线程访问共享变量时进行适当的同步,在Java中最常见的是使用关键字synchronized进行同步。

Java中共享变量的内存可见性问题

谈到内存可见性,我们首先来看看在多线程下处理共享变量时Java的内存模型。
在这里插入图片描述
Java内存模型规定,将所有的变量都存放在主内存中,当线程使用变量时,会把主内存里面的变量复制到自己的工作空间或者叫作工作内存,线程读写变量时操作的是自己工作内存中的变量。

Java内存模型是一个抽象的概念,那么在实际实现中线程的工作内存是什么呢?
在这里插入图片描述
一个双核CPU系统架构,每个核有自己的控制器和运算器,其中控制器包含一组寄存器和操作控制器,运算器执行算术逻辑运算。

每个核都有自己的一级缓存,在有些架构里面还有一个所有CPU都共享的二级缓存。那么Java内存模型里面的工作内存,就对应这里的L1或者L2缓存或者CPU的寄存器。

当一个线程操作共享变量时,它首先从主内存复制共享变量到自己的工作内存,然后对工作内存里的变量进行处理,处理完后将变量值更新到主内存。

那么假如线程A和线程B同时处理一个共享变量,会出现什么情况?

假设线程A和线程B使用不同CPU执行,并且当前两级Cache都为空,那么这时候由于Cache的存在,将会导致内存不可见问题,具体看下面的分析。

  • 线程A首先获取共享变量X的值,由于两级Cache都没有命中,所以加载主内存中X的值,假如为0。然后把X=0的值缓存到两级缓存,线程A修改X的值为1,然后将其写入两级Cache,并且刷新到主内存。线程A操作完毕后,线程A所在的CPU的两级Cache内和主内存里面的X的值都是1。
  • 线程B获取X的值,首先一级缓存没有命中,然后看二级缓存,二级缓存命中了,所以返回X=1;到这里一切都是正常的,因为这时候主内存中也是X=1。然后线程B修改X的值为2,并将其存放到线程2所在的一级Cache和共享二级Cache中,最后更新主内存中X的值为2。到这里一切都是好的。
  • 线程A这次又需要修改X的值,获取时一级缓存命中,并且X=1,到这里问题就出现了,明明线程B已经把X的值修改为了2,为何线程A获取的还是1呢?这就是共享变量的内存不可见问题,也就是线程B写入的值对线程A不可见。

那么如何解决共享变量内存不可见问题?使用Java中的volatile关键字就可以解决这个问题。

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

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

相关文章

适合前后端开发的可视化编辑器(拖拽控件)

分享一个面向研发人群使用的前后端分离的低代码软件——JNPF。 JNPF与市面上其他的低代码(轻流、宜搭、微搭、简道云、轻流、活字格等等),后者更倾向于非编程人员使用,让业务线人员自行构建应用程序。而 JNPF 这款低代码产品是面向…

【STM32学习】硬件CRC与传统CRC-32计算的不同点

硬件CRC与传统CRC-32计算的不同点 1、stm32的硬件CRC32与传统CRC-32有何不同?2、解决办法 1、stm32的硬件CRC32与传统CRC-32有何不同? ①STM32F103的硬件CRC校验是对整个32位字进行CRC计算,传统的CRC-32是逐字节的计算。 ②STM32的硬件CRC32的…

美食管理与推荐系统Python+Django网站系统+协同过滤推荐算法【计算机课设】

一、介绍 美食管理与推荐系统。本系统使用Python作为主要开发语言开发的一个美食管理推荐网站平台。 网站前端界面采用HTML、CSS、BootStrap等技术搭建界面。后端采用Django框架处理用户的逻辑请求,并将用户的相关行为数据保存在数据库中。通过Ajax技术实现前后端的…

【ThreeJS入门——】WEB 3D可视化技术——threejs

简介 网页上已经可以做出很多复杂的动画,精美的效果。下图就是通过WebGL在网页中绘制高性能的3D图形。 threejs是一个让用户通过javascript入手进入搭建webgl项目的类库。 1、搭建第一个场景和物体 三维的物体要渲染在二维的屏幕上。首先要创建一个场景来放置物体…

ASP.NET可视化流程设计器源码

源码介绍: ASP.NET可视化流程设计器源码已应用于众多大型企事业单位。拥有全浏览器兼容的可视化流程设计器、表单设计器、基于角色的权限管理等系统开发必须功能,大大为您节省开发时间,是您开发OA.CRM、HR等企事业各种应用管理系统和工作流系统的最佳基…

技术旅程分享:收获与成长的探索

2023年对我而言是充满挑战和机遇的一年,我在这段时间里积累了丰富的技术经验和个人成长。通过不懈努力和持续学习,我在技术领域迈出了一系列坚实的步伐。在这篇文章中,我将分享我在这段时间中的收获和技术成长经历,与CSDN的朋友们…

Vue实现加减法验证码

引入Vue.js 在HTML文件的<head>标签中引入Vue.js的CDN链接&#xff1a; <script src"https://cdn.jsdelivr.net/npm/vue2.6.11/dist/vue.min.js"></script>创建Vue实例 接下来&#xff0c;我们要创建一个Vue实例&#xff0c;并将其挂载到HTML文…

MIT 6.s081 实验解析——labs2

系列文章目录 MIT 6.s081 实验解析——labs1 MIT 6.s081 实验解析——labs2 文章目录 系列文章目录测试判断流程System call tracingsysinfo![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/ab9ca34f1fc64b6aa1df74613dc1a397.png) 测试判断流程 完成代码后将.c文…

领取的试用云服务器在哪

系列文章目录 华为云服务器试用领取 领取的试用云服务器在哪 文章目录 系列文章目录步骤如下 步骤如下 领取完之后在官网下找 在下面找到华为云耀云服务器L实例。 点击进入。 点击HECS。 即可找到自己的云服务器。 需要注意所勾选的地址&#xff0c;选完自己云服务器的地址…

msckf-vio 跑Euroc数据集,并用evo进行评估

所需材料&#xff1a; Euroc数据集主页&#xff1a;https://projects.asl.ethz.ch/datasets/doku.php?idkmavvisualinertialdatasetsevo评估工具代码&#xff1a;https://github.com/MichaelGrupp/evo向msckf-vio中添加保存位姿的代码&#xff0c;可参考https://blog.csdn.ne…

阿里云服务器地域如何选择?

阿里云服务器地域和可用区怎么选择&#xff1f;地域是指云服务器所在物理数据中心的位置&#xff0c;地域选择就近选择&#xff0c;访客距离地域所在城市越近网络延迟越低&#xff0c;速度就越快&#xff1b;可用区是指同一个地域下&#xff0c;网络和电力相互独立的区域&#…

el-select显示不全

css代码&#xff1a; .el-select-dropdown__wrap.el-scrollbar__wrap {margin-bottom: 0 !important; }

书生·浦语大模型第二课作业

作业一&#xff1a;小故事创作 作业要求&#xff1a;使用 InternLM-Chat-7B 模型生成 300 字的小故事&#xff08;需截图&#xff09; 完成情况&#xff1a; 作业二&#xff1a;熟悉 hugging face 下载功能 作业要求&#xff1a;熟悉 hugging face 下载功能&#xff0c;使用…

Kafka_02_Producer详解

Kafka_02_Producer详解 ProducerProducerRecordSend&Close实现原理ProducerInterceptorSerializerPartitioner 事务 Producer Producer(生产者): 生产并发送消息到Broker(推送) Producer是多线程安全的(建议通过池化以提高性能)Producer实例后可发送多条消息(可对应多个P…

【Docker】配置阿里云镜像加速器

默认情况下&#xff0c;将来从docker hub &#xff08;https://hub.docker.com )上下载镜像太慢&#xff0c;所以一般配置镜像加速器。 没有账号的注册一个账号并登录 登录之后点击控制台 查看 cat /etc/docker/daemon.json

大学物理实验重点——电路暂态过程

RC串联电路的暂态过程&#xff1a; RLC串联电路的暂态过程&#xff1a; 三种解&#xff1a; 半衰期测量法测量时间常数&#xff1a; 测振荡周期&#xff1a; 不断增大电阻直至振荡凸起峰刚好消失&#xff0c;此时即为临界阻尼状态&#xff0c;记下电阻箱的阻值R&#xff0c;…

【微服务】springcloud集成skywalking实现全链路追踪

目录 一、前言 二、环境准备 2.1 软件环境 2.2 微服务模块 2.3 环境搭建 2.3.1 下载安装包 2.3.2 解压并启动服务 2.3.3 访问web界面 三、搭建springcloud微服务 3.1 顶层公共依赖 3.2 用户服务模块 3.2.1 准备测试使用数据库 3.2.2 添加依赖 3.2.3 添加配置文件 …

HDU 1205:吃糖果 ← 鸽巢原理

【题目来源】http://acm.hdu.edu.cn/showproblem.php?pid1205【题目描述】 HOHO&#xff0c;终于从Speakless手上赢走了所有的糖果&#xff0c;是Gardon吃糖果时有个特殊的癖好&#xff0c;就是不喜欢将一样的糖果放在一起吃&#xff0c;喜欢先吃一种&#xff0c;下一次吃另一…

cgo环境之-安装gcc mingw

下载 到官网下载&#xff1a; 官网 如果你是Windows arm 芯片&#xff0c;可以到这里下载 https://github.com/mstorsjo/llvm-mingw/releases

10款有趣的前端源码分享(附效果图及在线演示)

分享10款非常有趣的前端特效源码 其中包含css动画特效、js原生特效、svg特效以及小游戏等 下面我会给出特效样式图或演示效果图 但你也可以点击在线预览查看源码的最终展示效果及下载源码资源 自毁按钮动画特效 自毁按钮动画特效 点击打开盒子可以点击自毁按钮 进而会出现自毁…