zoukankan      html  css  js  c++  java
  • Java知识整理(10)—— volatile

    为什么要用volatile?
    为什么要用volatile,它可以解决两个问题:
    • 保证不同线程对同一个变量进行操作时的可见性问题;
    • 禁止进行指令重排序。
    1.可见性问题
    可见性问题是JAVA并发编程中的基本概念:
    官方定义如下:
    可见性是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看的见。
    为什么出现可见性问题?
    在并发编程中,不同的线程在不同的cpu执行着,而CPU的缓存机制长这样:
    若线程1运行在CPU1上,线程2运行在CPU2上,当线程1修改了某一个对象的值时,可能会缓存在cache1(若cache1满了则缓存在cache2中,以此内推),没有写进主存,那线程2就无法读到最新的数据,因此不能实现可见性。
    volatile的作用就是被volatile修饰的变量被修改时强制立即写进主存中,让cache失效,这样其他读该变量的线程就可以立即读到最新的值。这就是volatile的作用之一。
    2.有序性问题
    有序性是Java并发编程中的另一概念,有序性指程序执行的顺序按照代码的先后顺序进行,而指令重排序是指在执行程序时,编译器和处理器为了提高代码执行效率,会对没有数据依赖的代码行进行重排序,在保证程序最终结果不受影响的情况下更高效地完成代码的运行。不管怎么重排序,单线程执行结果不会被改变,但会影响多线程并发执行的正确性。
    举个栗子:
    线程1执行下面这段代码: 线程2执行下面这段代码:
    Object o = new Object(); //1 if(flag){ //3
    boolean flag = true; // 2 o.method(); //4
    }
     
    说明:因为1和2不存在数据依赖,若重排序2比1先执行,那么3和4就会出错。
    在Java里面,可以通过volatile关键字来保证一定的“有序性”。volatile关键字禁止指令重排序,在代码前面添加内存屏障从而禁止指令重排。
    volatile关键字禁止指令重排序有两层意思:
    • 当程序执行到volatile变量的读操作或者写操作时,在其前面的操作的更改肯定全部已经进行,且结果已经对后面的操作可见;在其后面的操作肯定还没有进行;
    • 在进行指令优化时,不能将在对volatile变量访问的语句放在其后面执行,也不能把volatile变量后面的语句放到其前面执行。
    如果一个变量被volatile修饰,JMM会在写入这个字段之后插入一个wirite-Barrier指令,并在读这个字段之前插入一个read-barrier指令。具体如何实现的请看这篇博客,写的很好:http://www.infoq.com/cn/articles/java-memory-model-4/
    volatile有哪些不行的?
    不能保证原子性。它仅能够对原始变量操作保证原子性,不能对复合操作保证原子性。只有借助synchronized和Lock。
    优秀参考博文:
     
  • 相关阅读:
    ural(Timus) 1019 Line Painting
    ACMICPC Live Archive 2031 Dance Dance Revolution
    poj 3321 Apple Tree
    其他OJ 树型DP 选课
    poj 3548 Restoring the digits
    ACMICPC Live Archive 3031 Cable TV Network
    递归循环获取指定节点下面的所有子节点
    手动触发asp.net页面验证控件事件
    子级Repeater获取父级Repeater绑定项的值
    没有列名的数据绑定
  • 原文地址:https://www.cnblogs.com/Gabby/p/6752225.html
Copyright © 2011-2022 走看看