volatile为什么不能保证原子性的思考

1、故事的起因:

        前几天有人问过关于volatile关键字的一些问题, 想起了自己刚接触这个关键字时候存在的疑惑,赶上今天有时间就整理了一些自己的想法。

        首先,需要明确的一点是,volatile关键字修饰的变量可以保证该变量操作的有序性和可见性, 但是保证不了操作的原子性。

        关于volatile关键字修饰的变量在确保变量操作的有序性和可见性的介绍其他文章已经有很详细的介绍了,也比较通俗易懂,这里针对这两点就不再赘述了。

        但是关于volatile关键字为什么不能保证操作的原子性的问题刚开始我感到比较迷惑(虽然也查了一些文章,但是还是不能理解,可能是因为我比较愚钝,O(∩_∩)O哈哈~),经过几番脑神经搏斗终于找到了一个能说服自己的解释,但是不知道理解的是否准确。故而,在这里写下这些文字,一方面是想给同样跟我一样有这样困惑的小伙伴提供一个思路,另一方面也是希望各位大神关于我这个理解是否存在偏差给出一些指点^_^。

2、问题的阐述

         网上就volatile关键字的原子操作的介绍中大多用的是对int类型的变量进行自增操作的例子介绍的, 那我们也索性就用这个例子来继续阐述吧。

         private volatile int i = 0;

         i++;

         上边的代码中的变量i是被volatile修饰的,他在下边做i++操作的时候在多线程环境中并不安全,不安全的原因就是i++这个操作是非原子性的操作。

         以下从“引用开始”标志到“引用结束”标志中的阐述是我对比较多的网上其他文章对i++操作不安全的解释的理解

          /*******************引用开始****************************/

      如果在起比较多的线程,比如起了500条线程并发地去执行i++这个操作  最后的结果i是小于500的,解释是:

       i++操作可以被拆分为三步:

             1,线程读取i的值

             2、i进行自增计算

             3、刷新回i的值

          假设某一时刻i=5,此时有两个线程同时从主存中读取了i的值,那么此时两个线程保存的i的值都是5, 此时A线程对i进行了自增计算,然后B也对i进行自增计算,此时两条线程最后刷新回主存的i的值都是6(本来两条线程计算完应当是7)所以说volatile保证不了原子性。

         /*******************引用结束**********************/

        看完以上的解释我的不解之处在于,既然i是被volatile修饰的变量,那么对于i的操作应该是线程之间是可见的啊,就算A.,B两个线程都同时读到i的值是5,但是如果A线程执行完i的操作以后应该会把B线程读到的i的值置为无效并强制B重新读入i的新值也就是6然后才会进行自增操作才对啊。(这是我当时所存在的疑惑O(∩_∩)O哈哈~)

3、问题的自我解释

         上边的问题困扰了我有一段时间,而且我从网上搜索的文章的解释都大同小异(可能是我搜索的姿势不对^_^)导致我始终困在那个圈里。

          有一天我坐在回家的车上又想到了这个问题,忽然把这个问题想通了(也可能是自己在骗自己0.0)(ps:由此看来,做开发需要多回家O(∩_∩)O哈哈~)

          首先我觉得对i++这个操作需要更细的拆分

           1,线程读取i

            2,i++  > i = i + 1 > (1) temp = i + 1, i = temp

          当i=5的时候A,B两个线程同时读入了i的值, 然后A线程执行了 temp = i + 1的操作, 要注意,此时的i的值还没有变化,然后B线程也执行了 temp = i + 1的操作,注意,此时A,B两个线程保存的 i的值都是5,temp的值都是6, 然后A线程执行了 i = 6(temp)的操作,此时i的值会立即刷新到主存并通知其他线程保存的i值失效, 此时B线程需要重新读取i的值那么此时B线程保存的i就是6,同时B线程保存的temp还仍然是6, 然后B线程执行i=6(temp),所以导致了计算结果比预期少了1。

以上是我个人自己的理解,仅供曾经也被同样问题困惑过的小伙伴参考同时希望大神们可以指正出其中理解存在偏差的地方。

本博客为本人原创, 转载请告知.

  • 9
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 20
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值