volatile解析

volatile解析

 volatile这个关键字可能很多朋友都听说过,或许也都用过,但是在java5以后这个关键字发出了异样的光芒。

volatile特性

1.保证内存可见性

2.防止指令重排

首先先带领大家了解一下java的内存模型中的内存可见性,和原子性。

可见性:

 可见性,是指线程之间的可见性,一个线程修改的状态对另一个线程是可见的。也就是一个线程修改的结果。另一个线程马上就能看到。

原子性:

     原子是世界上的最小单位,具有不可分割性,比如i = 0 ,这个操作是不分割的,但是i++(i=i+1)这种操作是可以分割的,所以i++就是一个非原子性的操作,在java中使用同步技术(sychronized)来让它变成一个原子操作。一个操作是原子操作,那么我们称它具有原子性。

指令重排序:

        在JDK中,为了保证程序的最终运行结果需要和在单线程严格意义的顺序化环境下执行的结果一致,程序指令的执行顺序有可能和代码的顺序不一致,这个过程就称之为指令的重排序。但是在大并发或者多数据的时候,指令重新排序后不能保证数据的准确性,所以在java的内存模型中推出了happend-before原则,简单的说就是动作B要看到动作A的执行结果(无论A/B是否在同一个线程中),那么A/B必须满足happens-before原则,但是在了解happend-before原则之前还要了解一下java的动作模型: 编写读、变量写、监视器加锁、释放锁、线程启动(start)、线程等待(join).

   happend-before:

            (1)同一个线程中的每个Action都happens-before于出现在其后的任何一个Action。

       (2)对一个监视器的解锁happens-before于每一个后续对同一个监视器的加锁。

        (3)对volatile字段的写入操作happens-before于每一个后续的同一个字段的读操作。

        (4)Thread.start()的调用会happens-before于启动线程里面的动作。

        (5)Thread中的所有动作都happens-before于其他线程检查到此线程结束或者Thread.join()中返回或者Thread.isAlive()==false。

        (6)一个线程A调用另一个另一个线程B的interrupt()都happens-before于线程A发现B被A中断(B抛出异常或者A检测到B的isInterrupted()或者interrupted())。

        (7)一个对象构造函数的结束happens-before与该对象的finalizer的开始

        (8)如果A动作happens-before于B动作,而B动作happens-before与C动作,那么A动作happens-before于C动作。


OK,在happend-before中有提到了volatile关键字,先来说说volatile关键字是怎么保证线程之前的内存可的。

java中所有的共享变量存储在主内存中,每个线程都有一个私有的本地内存,本地内存保存了被该线程使用到的主内存的副本拷贝,线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存中的变量。这三者之间的交互关系如下:


比如A ,B中的本地内存中都存放这i=1;但是当线程A对i进行了自增,i=2,但是 i=2并没有推送到主内存中,所以在线程B的本地内存中i的值还是1这样就造成了数据最后不准确。但是volatile保证了这一点。他是怎么做的那,

首先每个cpu中都是寄存器,1级缓存,2级缓存..  ,线程A 中volatile 对写变量 进行了storeLoad (指令) i  =2   storeStore(指令),把本地内存中的副本push到主内存中,线程B中 来读取i的值的时候volatile 读变量时候添加LoadLoad(指令)和LoadStore(指令)强制把i的最新值刷新到本地内存B中。但是,上文提到了volatile有happend-before原则, 所以

class VolatileTest{
    int x = 0;
    volatile boolean v = false;
    public void writer() {
        x = 42;
        v = true;    

    }

   public void reader() {
    if (v == true) {
    //这里可以看到x的值是 42.
    }
   }

}

在以上的代码中可以看到x的值是42,在执行写指令的时候会把所有的变量值推送到主内存中,在读执行的时候又会吧最新值推到线程B的工作内存中,所以很多优秀的框架中或者代码中使用了这个特性。

但是volatile并不保证原子性,volatile数组中的元素都不保证内存可见,volatile相当于半个sychronized。









       








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值