volatile不保证原子性

本文通过代码示例探讨了volatile关键字在Java中的使用,指出volatile不保证原子性,导致并发场景下可能出现数据不一致问题。通过分析`number++`操作的字节码,揭示了并发冲突的原因。为解决这个问题,文章引入了AtomicInteger,并展示了如何使用它来确保原子操作,从而避免并发问题。最后,展示了使用AtomicInteger后的正确输出结果。
摘要由CSDN通过智能技术生成

这里我们先来分析一段代码:


class MyData{

    volatile int number = 0;

   
    //请注意,此时number前面时加了volatile关键字修饰的,volatile不保证原子性
    public void addPlusPlus(){
        number ++;
    }

  
}



public class VolatileDemo {


    public static void main(String[] args) {
        MyData myData = new MyData();
        for (int i = 0; i < 20; i++) {
            new Thread(()->{
                for (int j = 0; j < 1000; j++) {
                    myData.addPlusPlus();
                    myData.addMyAtomic();
                }
            },String.valueOf(i)).start();
        }

        //需要等待上面20个线程全部计算完成后,再用main线程取得最终的结果看是多少
        while (Thread.activeCount() > 2){
            Thread.yield();
        }
        System.out.println(Thread.currentThread().getName() + "\t int type,finally number value:" + myData.number);

    }

    

}

如果volatile保证原子性,那么上段代码输出的结果就一定是20000,如果不保证原子性那么上面的代码可能输出小于20000的值。我们看下控制台输出:

这输出值小于20000,则说明volatile不保证原子性。 

解决方法:

1.使用synchronized关键字进行加锁(但是这个锁有点重了,在此不做讨论)

2.使用juc下的AtomicInteger

我们来看一下为什么会输出小于20000的值?

我们这里定义了一个全局变量number ,但是呢,我们看一下number++的字节码

 0 aload_0
 1 dup
 2 getfield #2 <VolatileDemo/MyData.number>
 5 iconst_1
 6 iadd
 7 putfield #2 <VolatileDemo/MyData.number>
10 return

在这里我们可以看到number++的执行共有四条指令(getfield->putfield),假设我们有两个线程分别是thread1和thread2,线程thread1执行完iadd后突然被挂起,这时thread2获得执行权之后thread2操作完变量number后将值写入主内存(参见volatile保证可见性)中,但是这时thread1也会将变量number写入到主内存中,此时就出现了并发问题。

解决后代码:


class MyData{


    AtomicInteger atomicInteger = new AtomicInteger();

    public void addMyAtomic(){
        atomicInteger.getAndIncrement();
    }
}



public class VolatileDemo {


    public static void main(String[] args) {
        MyData myData = new MyData();
        for (int i = 0; i < 20; i++) {
            new Thread(()->{
                for (int j = 0; j < 1000; j++) {
                    myData.addPlusPlus();
                    myData.addMyAtomic();
                }
            },String.valueOf(i)).start();
        }

        //需要等待上面20个线程全部计算完成后,再用main线程取得最终的结果看是多少
        while (Thread.activeCount() > 2){
            Thread.yield();
        }

        System.out.println(Thread.currentThread().getName() + "\t AtomicInteger type,finally number value:" + myData.atomicInteger);
    }


}

此时查看打印结果:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值