java编程语言容许线程访问共享变量,为了确保共享变量能被准确和一致的更新,线程应该确保经过排他锁单独得到这个变量。html
Java语言提供了volatile,在某些状况下比锁更加方便。若是一个字段被声明成volatile,java线程内存模型确保全部线程看到这个变量的值是一致的。java
若想清楚理解volatile
关键字是如何保障共享变量在多线程之间正常使用的须要了解如下几点编程
精简一点,概念以下:缓存
指令在CPU中执行,CPU运行速度较快,所以为减小从内存中频繁读写数据的开销,在cpu与内存的操做之间,有个高速缓存的的区域多线程
获取数据流程:并发
上面的流程中,第一步会致使一致性问题,分析以下编程语言
若内存中Data已更新,但缓存中数据未更新,此时返回缓存中Data,返回的是旧数据测试
解决方案:ui
java内存模型,主要是为了屏蔽不一样的硬件,操做系统的内存访问差别,使Java程序能够达到跨平台的目的,从而定义的一套模型操作系统
线程之间的共享变量存储在主内存中,每一个线程都有一个私有的本地内存,本地内存保存该线程读写共享变量的副本
所以也存在上面的一致性问题,即如何保证线程对共享变量的修改后,其余的线程能访问到最新的共享变量
指令重排序
Java内存模型中,容许编译器和处理器对指令进行重排序,可是重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性
举例说明
int i; boolean ans; i = 10; ans = true;
上面的代码中,i
和ans
的赋值前后顺序因为指令重排,可能会出现ans=true
时,i
依然为0的状况
原子性
表示不可再继续分割
可见性
一个线程对共享变量的修改,确保对其余线程可见(即另外一个线程能访问到修改后的数据)
volatile
进行声明变量,保证可见顺序行
程序执行的顺序按照代码的前后顺序执行
volatile
禁止指令重排用法
volatile
便可做用
volatile
修饰的共享变量时,确保前面的代码都执行完了)原理和实现机制
volatile
声明的共享变量,会强制要求修改后的值写入内存,并失效其余线程的本地内存中的副本1.volatile
关键字没法保证操做的原子性
2.volatile
关键字,禁止共享变量的指令重排,确保修改对全部线程当即可见
3.使用场景
int ans = i + j;
(也没法保障准确性)经典的单例case写法
class Singleton{ private volatile static Singleton instance = null; private Singleton() { } public static Singleton getInstance() { if(instance==null) { synchronized (Singleton.class) { if(instance==null) instance = new Singleton(); } } return instance; } }