• 详解volatile 关键字与内存可见性


        先来看一个例子:

    1. public class VolatileTest {  
    2.     
    3.     public static void main(String[] args) {  
    4.         ThreadDemo td = new ThreadDemo();  
    5.         new Thread(td).start();  
    6.     
    7.         while (true) {  
    8.             if (td.isFlag()) {  
    9.                 System.out.println("================");  
    10.                 break;  
    11.             }  
    12.         }  
    13.     }  
    14. }  
    15.     
    16. class ThreadDemo implements Runnable {  
    17.     private boolean flag = false;  
    18.     
    19.     @Override  
    20.     public void run() {  
    21.         try {  
    22.             Thread.sleep(200);  
    23.         } catch (InterruptedException e) {  
    24.     
    25.         }  
    26.         flag = true;  
    27.         System.out.println("falg=" + flag);  
    28.     }  
    29.     
    30.     public boolean isFlag() {  
    31.         return flag;  
    32.     }  
    33.     
    34.     public void setFlag(boolean flag) {  
    35.         this.flag = flag;  
    36.     }  
    37. }  

    两个线程,一个改flag的值,主线程做判断,结果:

     

    主线程的flag貌似还是false,按理通过Runnable创建的线程访问的应该是共享数据,那为什么会出现这种情况?这就涉及到内存可见性。

    JVM会为每个线程分配一个独立缓存提高效率。上述例子中我们先在主存中开辟一块内存,如图:

    那么这个两个线程,一个是读(主线程),一个是写(线程1),我们让线程1睡了200ms,说明,线程1先执行,每个线程都有一个独立的缓存,也就是说当线程1需要对主存的共享数值进行改变,它需要先把这个flag复制一份到缓存区中,

    然后修改,将来再把这个值写回主存去,在写之前,主线程来了,它要读取现在在内存里面的值,现在是false,当然有一种情况,就是线程1在某个机会将flag=true写回去,

    当时主线程用了while(true),这句话调用了系统底层代码,效率极高,高到主线程没有机会再次读取内存,这就是线程对共享数据操作的不可见。

    内存可见性问题:当多个线程操作共享数据时,彼此不可见。

    如何解决?同步锁。

    但是用了锁,代表效率极低,但是我现在我不想加锁,但是有存在内存可见性的问题,我该怎么办?

    关键字volatile:当多个线程进行操作共享操作时,可以保证内存中的数据可见。(内存栅栏,实时刷新)

    我们可以认为它是直接在主存操作的,这个实时刷新的操作相比不加,性能略低,但是比加锁的效率显然高很多,低在哪?加了这关键字,JVM就不能进行指令重排序,无法优化代码执行

    1. public class VolatileTest {  
    2.     
    3.     public static void main(String[] args) {  
    4.         ThreadDemo td = new ThreadDemo();  
    5.         new Thread(td).start();  
    6.     
    7.         while (true) {  
    8.             if (td.isFlag()) {  
    9.                 System.out.println("================");  
    10.                 break;  
    11.             }  
    12.         }  
    13.     }  
    14. }  
    15.     
    16. class ThreadDemo implements Runnable {  
    17.     private volatile boolean flag = false;  
    18.     
    19.     @Override  
    20.     public void run() {  
    21.         try {  
    22.             Thread.sleep(200);  
    23.         } catch (InterruptedException e) {  
    24.     
    25.         }  
    26.         flag = true;  
    27.         System.out.println("falg=" + flag);  
    28.     }  
    29.     
    30.     public boolean isFlag() {  
    31.         return flag;  
    32.     }  
    33.     
    34.     public void setFlag(boolean flag) {  
    35.         this.flag = flag;  
    36.     }  
    37. }  

    volatile相对synchronized是一种轻量级同步策略。但是注意:

    1. volatile不具备互斥性
    2. volatile不能保证变量的原子性
  • 相关阅读:
    (十)条件判断
    (九)字符处理命令
    (八)awk命令
    (六)环境变量配置文件
    (七)grep命令行提取符号
    Ⅶ 类模板与STL编程 ②
    Ⅵ 虚函数与多态性
    Ⅴ 运算符重载
    Ⅳ 继承与派生②
    Ⅳ 继承与派生①
  • 原文地址:https://www.cnblogs.com/figsprite/p/10779904.html
Copyright © 2020-2023  润新知