首页 > 其他分享 >关于volatile关键字为什么不能保证原子性(图文分析)

关于volatile关键字为什么不能保证原子性(图文分析)

时间:2024-08-17 21:55:21浏览次数:11  
标签:保证 关键字 线程 内存 操作 volatile 数据 图文

文章目录

概要

在网上的很多文章当中,都说到了volatile不可以保证原子性,对于这个关键字的定义解释的很清楚。volatile 是 Java 中的一个关键字,用于修饰变量,它的主要作用是保证变量的可见性和禁止指令重排序。 但是对于为什么这个关键字不能保证原子性这块逻辑的分析又感觉到差强人意、一笔带过,今天题主尝试着解答一下这个问题,如有错误欢迎大家批评与指正!

多线程访问下数据的问题

对于多线程的数据访问,其实是跟我们的JMM内存模型有关系,在java内存模型当中的定义,所有的数据都会写到主内存当中,其它的数据需要操作时,将主内存的数据copy一份到自己线程私有的内存空间使用,操作完成后再将数据写回到主内存当中。`所以这个时候就出现了问题,我写回去了,其他的线程如果不通知的话,是不是一直感知不到。
按照下图所示:假设cpu是按照步骤顺序执行,a未加volatile关键字,请问一下步骤4和步骤6,打印出来的值是多少?很明显打印出来的都是10,因为线程2感知不到主内存的变化,所以打印的值不会收到影响。如果我将a进行volatile进行修饰了,那么步骤4和步骤6打印出来的值又会是多少了?这回打印的为10和11,因为加了volatile,所以线程能感知到主内存的变化,不会再使用线程内保存的数据,会从主内存读取。
在这里插入图片描述
那么问题来了,这么看好像是保证了print函数的原子性了啊。首先我们要清楚print函数肯定也不是原子性操作,第一步:加载数据到本地;第二步:打印数据。那为什么感觉像是能保证print函数的原子性了?那是因为print函数并未对a值进行二次操作,导致了print函数像是原子性函数一样,那可不就原子性了。之所有出现了非原子性的操作,不就是因为多个线程对数据进行了修改嘛。
其实答案一直在volatile关键字的定义当中,volatile保证了可见性。那么问题来了volatile保证了谁的可见性?保证的是其他的线程的可见性。保证可见性的触发时机是什么?这个动作必须要有一个指令去触发,所有的需要对这个a值进行操作的指令应该都可以。还拿上图来举例,假设步骤6什么也不做,这个时候的a对于线程2来说是多少?这个时候的值是valid,是失效的状态,所有的对于这个的值的指令操作,发现这个值失效了,会从新到主内存去加载这个值的数据。
在这里插入图片描述
所有的对于a有后续的数据操作的,除了读数据,print数据这种不会对数据改动的操作。其他的操作都不能保证a的‘原子性。拿a=a+1来举例:
线程1:
1.加载数据到本地线程
2.对加载的数据+1
3.将本地线程数据写回到主内存
线程2:
1.加载数据到本地线程(如果这个操作之前,数据已经写回到主内存,就能保证a的原子性,但这是不可能的)
2.对加载的数据+1
3.将本地线程数据写回到主内存
假设:线程1走到第二步v=11(+1操作),然后线程2走到了第一步a=10(load操作),这个时候在切回到线程1的第三步a=v(写回主内存)。此时切回到线程2,线程二能感知到最新数据嘛?并不能,因为这个时候已经没有数据的load操作了,虽然主内存的数据已经变更了,且线程a的数据已经valid了(别问我这个时候为什么不会触发主内存往子线程去强制推数据,俺也不知道,别人对这个关键字的定义就是保证了可见性,可没保证帮你主动把你线程内的数据给你也同步成主内存的数据,估计很多人在这个地方晕了很久,题主之前也是这样想的,你保证可见性,意思是不是主内存变化了,就帮线程把数据也给更新为最新的。NO,别人只会将你的数据更新为不可用,只有你自己主动去加载,才能获取到最新的,以题主对于上述的命令的理解,对数据进行+1的操作并不会load数据。)

小结

关于volatile为什么不能保证原子性,题主通过图文的方式,带大家简单的理解一下,希望大家能通过这种方式去了解volatile这个关键字,我们只要记住官方的定义,别人只是保证了可见性和指令顺序性。可见性是怎么实现的,可见只的是对主内存可见,对于线程来说,在你未load之前,你都是不可见的,但是只要你有任何一个对于这个数据的操作都会触发load,所以看上去像是可见了。

标签:保证,关键字,线程,内存,操作,volatile,数据,图文
From: https://blog.csdn.net/m0_37903574/article/details/141269509

相关文章

  • 今天来一期关键字大全
    1.asmasm(指令字符串):允许在C++程序中嵌入汇编代码。2.autoauto(自动,automatic)是存储类型标识符,表明变量"自动"具有本地范围,块范围的变量声明(如for循环体内的变量声明)默认为auto存储类型。3.boolbool(布尔)类型,C++中的基本数据结构,其值可选为true(真)或者false(假)。C++......
  • Java基础——面向对象编程高级(常见关键字)
    package:用于声明一个类或接口所属的包(即命名空间)语法格式:package顶层包名.子包名OrderController类属于包com.hxzs.order.controller一个源文件只能有一个声明包的package语句package语句作为Java源文件的第一条语句出现。若缺省该语句,则指定为无名包。包名,属于标识符,满......
  • 面试题:在Java中,volatile 关键字的作用是什么?它与 synchronized 关键字在实现线程同步
    面试题:在Java中,volatile 关键字的作用是什么?它与 synchronized 关键字在实现线程同步方面有何不同?请深入探讨其背后的原理和应用场景。更多答案在这里,手机或电脑浏览器就可以打开, 面霸宝典【全 拼音】.com 这里可以优化简历,模拟面试,企业项目源码,最新最全大厂高并......
  • Python解释器如何下载+如何安装+配置环境+踩坑 一文搞定【保姆级图文教程】
    如果你要学Python,那么第一件事情就是先去安装。因为你的电脑里面没有Python,编写好的.py文件就没有解释器可以运行,所以安装Python环境/解释器就是最重要的一件事。PS:本文仅为笔记,为个人整理而成,如有不足之处请多多指正。目录第一步:下载1.官方网站2.镜像源网站第二步......
  • Oracle数据库中,MINUS是一个关键字
    在Oracle数据库中,MINUS是一个关键字,用于执行两个SELECT语句的差集操作。MINUS操作返回在第一个SELECT语句中出现但不在第二个SELECT语句中出现的所有行。换句话说,它会从第一个查询结果中减去第二个查询结果,只保留在第一个查询结果中存在而第二个查询结果中不存在的记录。基本用法......
  • MathType7.5破解版下载安装激活图文详细教程(附激活秘钥)
    ......
  • Java学习笔记5--关键字和保留字
    一、概念Java关键字(KeyWord):对Java的编译器有特殊的意义,他们用来表示一种数据类型或者表示程序的结构.保留字(ReserveWord):即它们在Java现有版本中没有特殊含义,以后版本可能会作为有特殊含义的词,或者该词虽然在Java中没有特殊含义,以后版本也不打算使用,但在其它语言中有特殊含义......
  • Navicat Premium v17 中文版 激活图文教程
    Navicat17全新升级,软件增强了数据库管理和数据分析的功能体验。其中包括模型设计与同步、数据字典、数据分析(dataprofiling)、用户体验、查询优化、BI功能集成MongoDB/Snowflake、专注模式、Redis哨兵模式与平台扩展LinuxARM等。此次升级让用户在数据库的创建、管理、......
  • 最新小红书矩阵批量起号玩全自动图文法,无脑操作轻松引流创业粉
    项目介绍:很多人对于引流觉得很难每天都在网上找各种各样的教程那么今天流量终结者来了小红书图文矩阵批量制作软件加小红书号商+流量回收渠道全都给你带来了这套玩法是我们一直以来自己使用的玩法相对其他引流方法这个是上量最快的也是玩法最简单的,这个软件可以给大家......
  • 最新小红书矩阵批量起号玩全自动图文法,无脑操作轻松引流创业粉
    项目介绍:很多人对于引流觉得很难每天都在网上找各种各样的教程那么今天流量终结者来了小红书图文矩阵批量制作软件加小红书号商+流量回收渠道全都给你带来了这套玩法是我们一直以来自己使用的玩法相对其他引流方法这个是上量最快的也是玩法最简单的,这个软件可以给大家......