zoukankan      html  css  js  c++  java
  • volitile的使用

    volatileche称为轻量级锁,被volatile修饰的变量,在线程之间是可见的。
    可见:一个线程修改了这个变量的值,在另一个线程中能够读到这个修改后的值
    synchronized除了线程之间互斥,还有一个非常大的作用,就是保证可见性

     1 /*
     2  * 保证可见性的前提
     3  * 
     4  * 多个线程拿到同一把锁,否则保证不了
     5  * 
     6  */
     7 public class Demo {
     8     private int a = 1;
     9 
    10     public synchronized int getA() {
    11         return a;
    12     }
    13 
    14     public synchronized void setA(int a) {
    15         try {
    16             Thread.sleep(10);
    17         } catch (InterruptedException e) {
    18             // TODO Auto-generated catch block
    19             e.printStackTrace();
    20         }
    21         this.a = a;
    22     }
    23     
    24     public static void main(String[] args) {
    25         Demo demo = new Demo();
    26         
    27         new Thread(new Runnable() {
    28 
    29             @Override
    30             public void run() {
    31                 demo.setA(10);    //保证这个线程先执行
    32             }
    33         }).start();
    34         
    35         
    36         new Thread(new Runnable() {
    37 
    38             @Override
    39             public void run() {
    40              System.out.println(demo.getA());
    41             }
    42         }).start();
    43         
    44         try {
    45             Thread.sleep(100);
    46         } catch (InterruptedException e) {
    47             // TODO Auto-generated catch block
    48             e.printStackTrace();
    49         }
    50          System.out.println("最终结果为:"+demo.getA());
    51     }
    52     
    53 }

    10
    最终结果为:10

    volatile的底层是怎样实现的?
    我们发现,在汇编的环境下,加了volatile来修饰的变量和没加volatile的区别是。加了volatile的比没volatile的多了一个lock指令。因此lock指令起来作用。因此让我们来看看什么是lock指令。
     
    什么是lock指令?
    在多处理器的系统上,(注意,目的是为了实现可见性!)
    1、将当前处理器缓存行的内容协会到系统内容(缓存行是缓存的最小单位)
    2、这个写回到内存的操作会使在其他CPU里缓存该内存地址的数据失效
    public class Demo2 {
        
        public volatile boolean run = false;
        
        public static void main(String[] args) {
            
            Demo2 d = new Demo2();
            new Thread(new Runnable() {
    
                @Override
                public void run() {
                    for(int i = 1; i<=10; i++) {
                        System.out.println("执行了第"+i+"次");
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }    
                        d.run = true;
                }
            }).start();
            
            
            
            
            new Thread(new Runnable() {
    
                @Override
                public void run() {
                    while(!d.run) {
                        //不执行
                    }
                    System.out.println("线程2执行了");
                }
            }).start();
        }
    }

    //执行了第1次
    //执行了第2次
    //执行了第3次
    //执行了第4次
    //执行了第5次
    //执行了第6次
    //执行了第7次
    //执行了第8次
    //执行了第9次
    //执行了第10次
    //线程2执行了

    java虚拟机的类加载,就是把硬盘的或网络上的等等的字节码文件加载到内存中(CPU的速度>缓存速度>内存速度>硬盘速度),当我们用了volatile来修饰变量的时候,虚拟机会把该变量缓存到我们CPU缓存中,而且会把变量写回到内存中(没有加volatile的话,则不会把变量写回到内存中)而写回到内存的这个操作,会使在其他CPU里缓存该内存地址的数据失效,缓存上没数据,只能在内存中读回来,这样就保证了变量的可见性,如果我们在同一个类中大量地使用volatile的话,那么cpu的缓存机制就失效了,那么就性能就降低了

    synchronized与volatile区别
    volatile不能保证变量的非原子性操作,只能保证可见性
    synchronized 可以保持变量的非原子性操作(如i++),也能保证可见性。
    就是说,能用上volatile的话,能用synchronized替换。用上了synchronized,不一定能用volatile替换
  • 相关阅读:
    PAT乙级-1037. 在霍格沃茨找零钱(20)
    PAT乙级-1041. 考试座位号(15)
    PAT乙级-1047. 编程团体赛(20)
    css3 实现 背景图片显示
    块级元素与行内元素(内联元素)的区别和联系
    JS变量
    导航条菜单的制作 滑动缓慢
    HTML中Id和Name的区别
    全面理解Javascript中Function对象的属性和方法
    理解盒子模型
  • 原文地址:https://www.cnblogs.com/quyangyang/p/10367924.html
Copyright © 2011-2022 走看看