• volatile


    volatile 有两个作用

    1 线程内存可见性

    2 指令排序

    可见性原理:

    线程在对Volatile变量执行写操作时强迫线程将最新的值刷新到主内存中,而在读操作时强迫从主内存中读入变量的值

     

     2 指令重排

    使用了volatile修饰的变量,在对改变量进行读写的时候会添加屏障规则;

    在讲指令重排之前先介绍内存屏障

    内存屏障(memory barrier)是一个CPU指令。这条指令可以确保一些特定指令的执行顺序,相当于在上下两条指令之间添加一个障碍,阻止指令交换位置执行。

    jvm提供了四种屏障规则:Load=>读,Store=>写

      1)LoadLoad屏障:对于这样的语句Load1; LoadLoad; Load2,在Load2及后续读取操作要读取的数据被访问前,保证Load1要读取的数据被读取完毕。
    (2)StoreStore屏障:对于这样的语句Store1; StoreStore; Store2,在Store2及后续写入操作执行前,保证Store1的写入操作对其它处理器可见。
    (3)LoadStore屏障:对于这样的语句Load1; LoadStore; Store2,在Store2及后续写入操作被刷出前,保证Load1要读取的数据被读取完毕。
    (4)StoreLoad屏障:对于这样的语句Store1; StoreLoad; Load2,在Load2及后续所有读取操作执行前,保证Store1的写入对所有处理器可见。它的开销是四种屏障中最大的。在大多数处理器的实现中,这个屏障是个万能屏障,兼具其它三种内存屏障的功能。

    举个例子:

      

    public class Test2 {
         T o = new T();
    }
    
    class T {
        int m = 2;
    }

    查看汇编代码

     主要关注5 9 12 三行代码

     5=》在内存中开辟一个空间用来给o对象使用,但是此时都是初始值,m=0;

     9=>调用T的构造方法,m=2;

     12=>讲o指向刚开辟的内存空间的地址

    此时如果进行指令重排很可能是先执行12 然后在执行9。这就是为什么懒加载双重锁创建单例对象时 为什么要用volatile修饰了来禁止指令重排。

    使用volatile修饰之后

    public class Test2 {
       volatile  T o = new T();
    }
    
    class T {
        int m = 2;
    }

    相当于在12行上线加了StoreStore StoreRead指令,从而不会让12和9调换位置

  • 相关阅读:
    WPS设置去广告
    Android,几款apk工具
    Eclipse 使用
    linux su和sudo命令的区别
    CentOS下安装SecureCRT的sz/rz工具包
    CentOS下安装SecureCRT的sz/rz工具包
    CentOS下安装SecureCRT的sz/rz工具包
    VMware虚拟机上网络连接(network type)的三种模式--bridged、host-only、NAT
    修改CentOS系统的默认启动级别
    修改CentOS系统的默认启动级别
  • 原文地址:https://www.cnblogs.com/Tony100/p/12931692.html
Copyright © 2020-2023  润新知