美文网首页
关键字: volatile

关键字: volatile

作者: 神之试炼者 | 来源:发表于2018-02-24 13:50 被阅读0次

    参考原文: http://www.importnew.com/18126.html
    基本是对原文的精简, 推荐阅读原文以获得详细讲解.

    volatile能够保证值在修改时会立即更新到主存. 当其他线程读取时读到的一定是最新的

    volatile关键字和java内存模型有关, 所以先了解下内存模型

    简述:
    cpu运行速度远快于对内存的读写, 为了加快速度, 增加了高速缓存. 而一旦增加缓存, 就会出现缓存一致性问题.

    解决思路:
    1. 在总线上加Lock;
    2. 通过缓存一致性协议;

    早期使用思路1解决问题, 但是这样的话其他cpu无法访问内存, 效率低下.
    所以出现了缓存一致性协议, 最出名的就是Intel的MESI协议.

    核心思路:
    当cpu写数据的时候, 如果发现操作的变量是共享变量, 即在其他cpu中也存在该变量的副本, 则发出信号通知其他cpu将该变量的缓存行置为无效状态. 让他们重新从内存中读取最新值.

    并发编程常见问题:
    1.原子性问题;
    2. 可见性问题; 一个线程修改了变量, 其他线程能够立马看到修改的值.
    3. 有序性问题;

    有序性

    虚拟机--指令重排序

    //好例子
    //线程1:
    context = loadContext();   //语句1
    inited = true;             //语句2
     
    //线程2:
    while(!inited ){
      sleep()
    }
    doSomethingwithconfig(context);
    

    语句1和语句2可能被重排, 导致线程2读取inited为true. 结果加载配置的时候却没加载到....

    指令重排序不会影响单线程的执行, 但是会影响线程并发执行的正确性.

    java内存模型

    java内存模型规定所有的变量都存在主存当中, 每个线程有自己的工作内存, 线程对变量的操作都必须在工作内存中进行, 而不能直接对主存进行操作, 并且每个线程不能访问其他线程的工作内存.

    x = 10;         //语句1   **原子性**
    y = x;         //语句2     **不是原子性**  包含两个动作: 1.读取x的值;  2.写入工作内存;(注意工作内存四个字)
    x++;           //语句3      **不是原子性**  三步: 读-改-写  
    x = x + 1;     //语句4     **不是原子性**  三步: 读-改-写  
    

    在32位平台上, 保存64位数据会分成两节. 导致不能保证原子性(现在据说已经实现原子性了?)...但是不论如何, 加上volatile关键字是良好的编程规范.

    synchronized和lock自然也能保证可见性. 只是性能上没有volatile更优. 请因地制宜, 合理使用.

    volatile的两层含义

    1. 保证了不同线程对这个变量操作时的可见性;
    2. 禁止进行指令重排序;

    "禁止指令重排序"的实际使用

    //线程1:
    context = loadContext();   //语句1
    volatile inited = true;             //语句2    加上volatile,保证语句2在语句1之后执行.
     
    //线程2:
    while(!inited ){
      sleep()
    }
    

    doSomethingwithconfig(context);

    volatile保证可见性, 却无法保证原子性.

    使用volatile关键字的两个条件:

    1. 对变量的写操作不依赖于当前值;
    2. 该变量没有包含在具有其他变量的不变式中;

    下面列举几个Java中使用volatile的几个场景。

    1.状态标记量

    volatile boolean flag = false;
    while(!flag){
        doSomething();
    }
    public void setFlag() {
        flag = true;
    }
    volatile boolean inited = false;
    //线程1:
    context = loadContext();  
    inited = true;            
     
    //线程2:
    while(!inited ){
    sleep()
    }
    doSomethingwithconfig(context);
    

    2.double check

    class Singleton{
        private volatile static Singleton instance = null;
     
        private Singleton() {
     
        }
     
        public static Singleton getInstance() {
            if(instance==null) {
                synchronized (Singleton.class) {
                    if(instance==null)
                        instance = new Singleton();
                }
            }
            return instance;
        }
    }
    

    相关文章

      网友评论

          本文标题:关键字: volatile

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