volatile原理理解
引子
看一段代码:
public class Demo { private int a= 1; public int getA() { return a; } public void setA(int a) { try { Thread.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } this.a = a; } public static void main(String[] args) { Demo demo = new Demo(); new Thread( () -> { demo.setA(10); } ).start(); new Thread( () -> { System.out.println(demo.getA()); } ).start(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("最终的值为=="+ demo.a); } }
运行结果:
发现,结果并不相同。
解决方式1:
运行结果:
除此以外,还有一种方式,用volatile:
public class Demo { private volatile int a = 1; public int getA() { return a; } public void setA(int a) { try { Thread.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } this.a = a; } public static void main(String[] args) { Demo demo = new Demo(); new Thread( () -> { demo.a = 10; } ).start(); new Thread( () -> { System.out.println(demo.a); } ).start(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("最终的值为==" + demo.a); } }
运行结果:
volatile的原理:
深入理解Volatile关键字及其实现原理
工作内存Work Memory其实就是对CPU寄存器和高速缓存的抽象,或者说每个线程的工作内存也可以简单理解为CPU寄存器和高速缓存。
那么当写两条线程Thread-A与Threab-B同时操作主存中的一个volatile变量i时,Thread-A写了变量i,那么:
Thread-A发出LOCK#指令
发出的LOCK#指令锁总线(或锁缓存行),同时让Thread-B高速缓存中的缓存行内容失效
Thread-A向主存回写最新修改的i
Thread-B读取变量i,那么:
Thread-B发现对应地址的缓存行被锁了,等待锁的释放,缓存一致性协议会保证它读取到最新的值
由此可以看出,volatile关键字的读和普通变量的读取相比基本没差别,差别主要还是在变量的写操作上。
lock指令
什么时候使用volatile
完