volatile为什么不能保证原子性

volatile为什么不能保证原子性首先要了解的是,volatile可以保证可见性和顺序性,这些都很好理解,那么它为什么不能保证原子性呢?可见性可见性与Java的内存模型有关,模型采用缓存与主存的方式对变量进行操作,也就是说,每个线程都有自己的缓存空间,对变量的操作都是在缓存中进行的,之后再将修改后的值返回到主存中,这就带来了问题,有可能一个线程在将共享变量修改后,还没有来的及将缓存中的变量返回给主存中,另外一个线程就对…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

首先要了解的是,volatile可以保证可见性和顺序性,这些都很好理解,那么它为什么不能保证原子性呢?

可见性

可见性与Java的内存模型有关,模型采用缓存与主存的方式对变量进行操作,也就是说,每个线程都有自己的缓存空间,对变量的操作都是在缓存中进行的,之后再将修改后的值返回到主存中,这就带来了问题,有可能一个线程在将共享变量修改后,还没有来的及将缓存中的变量返回给主存中,另外一个线程就对共享变量进行修改,那么这个线程拿到的值是主存中未被修改的值,这就是可见性的问题。

volatile很好的保证了变量的可见性,变量经过volatile修饰后,对此变量进行写操作时,汇编指令中会有一个LOCK前缀指令,这个不需要过多了解,但是加了这个指令后,会引发两件事情:

  • 将当前处理器缓存行的数据写回到系统内存
  • 这个写回内存的操作会使得在其他处理器缓存了该内存地址无效

什么意思呢?意思就是说当一个共享变量被volatile修饰时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去内存中读取新值,这就保证了可见性。

原子性

问题来了,既然它可以保证修改的值立即能更新到主存,其他线程也会捕捉到被修改后的值,那么为什么不能保证原子性呢?
首先需要了解的是,Java中只有对基本类型变量的赋值和读取是原子操作,如i = 1的赋值操作,但是像j = i或者i++这样的操作都不是原子操作,因为他们都进行了多次原子操作,比如先读取i的值,再将i的值赋值给j,两个原子操作加起来就不是原子操作了。

所以,如果一个变量被volatile修饰了,那么肯定可以保证每次读取这个变量值的时候得到的值是最新的,但是一旦需要对变量进行自增这样的非原子操作,就不会保证这个变量的原子性了。

举个栗子

一个变量i被volatile修饰,两个线程想对这个变量修改,都对其进行自增操作也就是i++,i++的过程可以分为三步,首先获取i的值,其次对i的值进行加1,最后将得到的新值写会到缓存中。
线程A首先得到了i的初始值100,但是还没来得及修改,就阻塞了,这时线程B开始了,它也得到了i的值,由于i的值未被修改,即使是被volatile修饰,主存的变量还没变化,那么线程B得到的值也是100,之后对其进行加1操作,得到101后,将新值写入到缓存中,再刷入主存中。根据可见性的原则,这个主存的值可以被其他线程可见。
问题来了,线程A已经读取到了i的值为100,也就是说读取的这个原子操作已经结束了,所以这个可见性来的有点晚,线程A阻塞结束后,继续将100这个值加1,得到101,再将值写到缓存,最后刷入主存,所以即便是volatile具有可见性,也不能保证对它修饰的变量具有原子性。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/157650.html原文链接:https://javaforall.net

(0)
上一篇 2022年7月27日 下午4:00
下一篇 2022年7月27日 下午4:00


相关推荐

  • RewriteCond指令格式

    RewriteCond指令格式RewriteCond指令格式语法:RewriteCondTestStringCondPattern[flags]RewriteCond指令定义一条规则条件。在一条RewriteRule指令前面可能会有一条或多条RewriteCond指令,只有当自身的模板(pattern)匹配成功且这些条件也满足时规则才被应用于当前URL处理。1、TestString是一个纯文本的字符串,除

    2022年6月13日
    29
  • pycharm代码整体缩进(左移右移)

    pycharm代码整体缩进(左移右移)整体右移 缩进 鼠标全选住要缩进的代码 按 tab 整体左移 反缩进 鼠标全选住要缩进的代码 按 tab shift

    2026年3月27日
    2
  • wireshark抓包工具详细说明及操作使用「建议收藏」

    wireshark抓包工具详细说明及操作使用「建议收藏」前言①wireshark是非常流行的网络封包分析软件,功能十分强大。可以截取各种网络封包,显示网络封包的详细信息。②使用wireshark的人必须了解网络协议,否则就看不懂wireshark。③

    2022年7月3日
    28
  • 上市ASCII 表省内发现!

    上市ASCII 表省内发现!

    2022年1月17日
    58
  • DropDownList1 .cs指定初始值

    DropDownList1 .cs指定初始值DropDownList1.Item.Inset(0,”李四”);//这是插入第一个值为李四;DropDownList.Items.FindByValue(“李四”).selected=true;//这是调用findbyvalue方法指定初始值;转载于:https://www.cnblogs.com/huichao1314/p/5420117.html…

    2022年7月18日
    19
  • 修复公路题解

    修复公路题解修复公路题目题目背景 AAA 地区在地震过后 连接所有村庄的公路都造成了损坏而无法通车 政府派人修复这些公路 题目描述给出 A 地区的村庄数 NNN 和公路数 MMM 公路是双向的 并告诉你每条公路的连着哪两个村庄 并告诉你什么时候能修完这条公路 问最早什么时候任意两个村庄能够通车 即最早什么时候任意两条村庄都存在至少一条修复完成的道路 可以由多条公路连成一条道路 输入格式第 111 行两个正整数 NNN 下面 MMM 行 每行 333 个正整数 x y tx y tx y t 告诉你这条公路连着 x yx yx y 两个村

    2026年3月18日
    3

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号