为什么volatile不能保证原子性(以共享变量自增为例)

为什么volatile不能保证原子性

对于i=1这个赋值操作,由于其本身是原子操作,因此在多线程程序中不会出现不一致问题,但是对于i++这种复合操作,即使使用volatile关键字修饰也不能保证操作的原子性,可能会引发数据不一致问题。

 private volatile int i = 0;
 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然后才会进行自增操作才对啊。

后来参照其他博客终于想通了:

  • 1、线程读取i
  • 2、temp = i + 1
  • 3、i = temp

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

后来通过这篇博客
https://www.cnblogs.com/kevinwu/archive/2012/05/02/2479464.html

public class Increment {
    private int id = 0;

    public void getNext(){
        id++;
    }
}

反编译后的代码

 public class Increment extends java.lang.Object{
    public Increment();
      Code:
       0:   aload_0
       1:   invokespecial   #1; //Method java/lang/Object."":()V
       4:   aload_0
       5:   iconst_0
       6:   putfield        #2; //Field id:I
       9:   return

    public void getNext();
      Code:
       0:   aload_0         //加载局部变量表index为0的变量,在这里是this 
       1:   dup                 //将当前栈顶的对象引用复制一份
       2:   getfield        #2; //Field id:I,获取id的值,并将其值压入栈顶
       5:   iconst_1            //将int型的值1压入栈顶
       6:   iadd                //将栈顶两个int类型的元素相加,并将其值压入栈顶
       7:   putfield        #2; //Field id:I,将栈顶的值赋值给id
       10:  return

    }
       2:   getfield        #2; //Field id:I,获取id的值,并将其值压入栈顶
       5:   iconst_1            //将int型的值1压入栈顶
       6:   iadd                //将栈顶两个int类型的元素相加,并将其值压入栈顶

确实有一个先将值存入一个临时变量就行操作的过程

  • 1、线程读取i
  • 2、temp = i + 1
  • 3、i = temp

参考文章
https://www.cnblogs.com/simpleDi/p/11517150.html
https://www.cnblogs.com/kevinwu/archive/2012/05/02/2479464.html

你可能感兴趣的:(为什么volatile不能保证原子性(以共享变量自增为例))