volitile的使用

匿名 (未验证) 提交于 2019-12-02 23:05:13

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替换

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!