zoukankan      html  css  js  c++  java
  • 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调换位置

  • 相关阅读:
    【转】Windows Phone的应用程序认证要求
    ObservableCollection删除问题
    国庆总结?
    .net dll破解实战
    理理头绪
    创建Metro风格的WPF界面
    Alpha项目测试
    原型设计
    团队项目总结
    最常用的35中心里效应
  • 原文地址:https://www.cnblogs.com/Tony100/p/12931692.html
Copyright © 2011-2022 走看看