Java虚拟机规范中试图定义一种java内存模型(Java Memory Model)来屏蔽掉各种硬件和操作系统的内存访问差异,以实现让java程序在各种平台下都能达到一致的内存访问效果。在此之前,主流程序语言(如c、c++等)直接使用物理硬件和操作系统的内存模型,因此,会由于不同平台上内存模型的差异,有可能导致程序在一套平台上并发完全正常,而在另外一套平台上并发访问却经常出错,因此在某些场景就必须针对不同个平台来编写程序。
java内存模型
java内存模型的主要目标是定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节。此处的变量与java编程中所说的变量有所区别,它包括了实例字段、静态字段和构成数组对象的元素,但不包括局部变量与方法参数,因为后者是线程私有的,不会被共享,自然就不存在竞争问题。
java内存模型规定了所有的变量都存储在主内存中,每条线程还有自己的工作内存,线程的工作内存中保存了被该线程使用到的变量的主内存副本拷贝,线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存中的变量。不同的线程之间也无法直接访问对方工作内存中的变量,线程之间变量值得船体均需要通过主内存来完成。
内存间交互操作
线程独有的工作内存和主内存之间通过8种原子操作实现:
volatile变量的特殊规则
volatile变量具备两种特性:
第一,保证此变量对所有线程的可见性,即当一个线程改变了这个变量的值,新值对于其他线程来说是可以立即得知的;在工作内存中,每次使用volatile变量都必须先从主存输出最新的值,用于保证能看见其他线程对volatile变量所做的修改后的值,每次修改volatile变量后必须立刻同步回主内存,用于保证其他线程可以看到自己对volatile变量所做的修改。
第二,禁止指令重排序优化;
原子性、可见性与有序性
java内训模型是围绕着在并发过程中如何处理原子性、可见性和有序性这3个特征来建立的。
原子性:由java内存模型来直接保证的原子性变量操作包括read、load、use、assign、store、write,我们大致可以认为基本数据类型的访问读写是具备原子性的(long、double除外),如果需要一个更大范围内的原子性,可以使用同步代码块(synchronize关键字)。
可见性:可见性是指当一个线程修改了共享变量的值,其他线程能够立即得知这个修改。在这点上,volatile变量和普通变量的区别是,volatile的特殊规则保证了新值能立即同步到主内存,以及每次使用前立即从主内存刷新,因此,volatile保证了多线程操作时变量的可见性,而普通变量则不能保证这一点。
有序性:如果在本线程内观察,所有操作都是有序的(线程内表现为串行的语义);如果在一个线程中观察另一个线程,所有的操作都是无序的。