美文网首页
Volatile关键字

Volatile关键字

作者: 一凡呀 | 来源:发表于2018-02-03 14:42 被阅读0次

    内存屏障:

    内存屏障,又称内存栅栏,是一个CPU指令,基本上它是一条这样的指令:
    1、保证特定操作的执行顺序。
    2、影响某些数据(或则是某条指令的执行结果)的内存可见性。

    编译器和CPU能够重排序指令,保证最终相同的结果,尝试优化性能。插入一条Memory Barrier会告诉编译器和CPU:不管什么指令都不能和这条Memory Barrier指令重排序。

    Memory Barrier所做的另外一件事是强制刷出各种CPU cache,如一个 Write-Barrier(写入屏障)将刷出所有在 Barrier 之前写入 cache 的数据,因此,任何CPU上的线程都能读取到这些数据的最新版本。

    内存屏障.png

    这和java有什么关系?volatile是基于Memory Barrier实现的。

    如果一个变量是volatile修饰的,JMM会在写入这个字段之后插进一个Write-Barrier指令,并在读这个字段之前插入一个Read-Barrier指令。


    volatile.png

    这意味着,如果写入一个volatile变量a,可以保证:
    1、一个线程写入变量a后,任何线程访问该变量都会拿到最新值。
    2、在写入变量a之前的写入操作,其更新的数据对于其他线程也是可见的。因为Memory Barrier会刷出cache中的所有先前的写入。

    总结:

    特性一:保证变量在线程之间的可见性,可见性是基于CPU内存屏障指令,被JSR-133抽象为happens-before原则
    特性二:阻止编译时和运行时的指令重排,编译时JVM编译器遵循内存屏障的约束,运行时靠CPU屏障指令来阻止重拍
    不能实现原子性,
    例如:
    开启十个线程,每个线程中让静态变量count自增100次,最后的结果未必是1000,有可能少于1000
    因为count++操作不是原子性操作,
    原子性操作就是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch
    在多进程访问共享资源时,能够确保所有其他的进程(线程)都不在同一时间内访问相同的资源。原子操作(atomic operation)是不需要synchronized,这是Java多线程编程的老生常谈了。所谓原子操作是指不会被线程调度,机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch (切换到另一个线程)。通常所说的原子操作包括对非long和double型的primitive进行赋值,以及返回这两者之外的primitive。之所以要把它们排除在外是因为它们都比较大,而JVM的设计规范又没有要求读操作和赋值操作必须是原子操作(JVM可以试着去这么作,但并不保证)。

    一个变量在能够用volatile变量修饰的前提条件是
    1.运行结果不依赖变量的当前值
    2.变量不需要与其他状态的变量共同参与不变约束

    本文参考 :https://www.jianshu.com/p/d3fda02d4cae 占小狼

    相关文章

      网友评论

          本文标题:Volatile关键字

          本文链接:https://www.haomeiwen.com/subject/kzfuzxtx.html