最通俗易懂的volatile关键词详解

一、volatile能保证可见性

 在描述可见性之前,首先要讲解一下Java的内存模型,Java内存模型规定了了所有变量都存储在主存中,每条线程中还有自己的工作内存,线程的工作内存内保存了线程所使用到的变量,这些变量是从主存中拷贝而来,不同线程的工作内存互相隔离,线程间的变量值传递都要通过主存;线程对变量的所有操作(读取、赋值)都必须在工作内存中进行。
 在这种内存模型下,很有可能产生脏读现象。 如在某个线程执行语句:i = 1;
 Java虚拟机是这样运行的:先把i读进到工作内存中,然后对变量i所在的工作内存进行赋值操作,最后写回到主存。
 在这种机制下,很容易让其他线程无法读到最新的值,因为很有可能在某个线程做完赋值操作,但是还未做回写操作就进入其他状态暂时未往下执行了,这时候这个新值对于其他线程是不可见的。
 但是在使用volatile修饰变量后,会强制将修改的值立即写回主存。

二、volatile不能保证原子性

考虑一个自增操作:i++,这个操作需要经历四步:(1)读取i变量到工作内存 (2)对变量做+1操作(3)将变量写回主存。这三步在进行过程中,volatile并不能保证这三步会一起执行完或一条也不执行完,其他线程在这三步执行过程中也可以对i进行操作,所以无法保证原子性。

三、volatile能保证有序性

 volatile可以禁止部分指令重排序,即能在一定程度上保证指令的有序性。 何为指令重排序? 先看一段代码
        //线程1
        int result = cacu();//语句1
        boolean ok = true;//语句2

        //线程2
        while (!ok){
            //sleep
        }
        use(result);//语句3
 Java虚拟机不会按顺序执行这些语句编译后的指令,可能会先执行语句2,再执行语句1,这样的话可能会导致大问题,如果线程1先执行了语句2而未来得及执行语句1,线程2察觉到ok=true,则直接执行语句3,而这时result并未赋值。
 但是在Java虚拟机不会对互相有依赖关系的指令进行重排序,比如说 a = b + c; d = a / 2;这两条语句,就不会被重排序。
 但是如果对ok变量加上volatile关键字,那就不一样了,volatile为修饰的变量提供了一层内存屏障,在字节码中是在store指令后会有lock add1指令,就代表 在volatile指令修饰变量的操作指令前的指令都会先于该指令执行,即语句1会先于语句2执行,在volatile指令修饰变量的操作指令后的指令都会后于该指令执行。即语句2后面的语句都会后于语句2执行。
 因此volatile关键字可以保证有序性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值