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