java内存模型作用是屏蔽掉各种硬件和操作系统的访问差异,来实现让java语言在不同系统平台下都能达到一致的访问效果。
java内存模型的主要目标是定义程序中各个变量的访问规则,即将虚拟机中将变量存储到内存和从内存中取出变量这些底层细节。
这里的变量并不是仅仅指的是java中变量,还有实例字段、静态字段等等。
1.主内存和工作内存
主内存:java模型规定所有的变量都存在了主内存。
工作内存:是每条线程自己的内存。
当线程工作时,把主内存数据复制到工作内存中
主内存和工作内存的关系其实就像数据库和客户端的关系,主内存相当于一个数据库来存储数据,而客户端从数据库找到数据复制到本地内存,然后在呈现给你看。个人理解
2.内存之间的交互操作
从主内存到工作内存交互,java内存模型定义了8种操作完成。
每种操作都是原子的、不可再分的。
lock(锁定):作用于主内存变量,它把一个变量标识为线程独占的状态
unlock(解锁):作用于主内存变量,它把一个处于锁定状态的变量释放出来,释放出来才可以被其它线程锁定。
read(读取):作用于主内存变量,它把一个变量的值从主内存传输到线程工作的内存中。
load(载入):作用于工作内存变量,它把主内存获取的变量值放入工作内存变量的副本中。
use(使用):作用于工作内存变量,它将工作内存的一个变量值传送到工作引擎。
assign(赋值):作用于工作内存变量,它把工作引擎获取的值赋值给工作内存的变量。
store(储存):作用于工作内存变量,它把工作内存的变量传送给主内存。
write(写入):作用于主内存变量,它把从工作内存获取的变量的值放入主内存的变量中
在进行上述操作时,还要满足以下的规则:
a.不允许read和load、store和write操作单一出现
b.不允许线程丢失assign操作
c.不允许线程不进行assign操作
d.一个新的变量必须在主存中获取
e.一个变量在同一时刻只能被一个线程访问
f.一个变量指向lock操作,需要重新load或assign操作初始化变量
g.如果一个线程没有被lock,那也不能对其unlock
h.一个变量执行unlock,必须把这个变量同步到此内存。
3.volatile型变量特殊规则
volatile是java虚拟机提供的最轻量级的同步机制。
当一个变量加了volatile这个变量就是对所有线程是可见性的。
意思就是当对这个变量进行改变,就对所有线程都会通知这个值改变了。
它是如何操作呢?
本来read和load,store和write虚拟机是认为它们必须一起操作,但是加了volatile,这时就认为read load usd,assgin、store、write这时候虚拟机认为它们3个是一块的。当你进行了assgin那么你必须得保存。
volatile也不是在并发之下是安全的,只有在一些情况下是安全的。
4.long和double特殊规则
在虚拟机读取64位数据时,把读写操作分为两次32位操作来进行的。但是虚拟机却把这些具体实现成原子操作
5.原子性、可见性和有序性
原子性:就是他的每条指令是不可以在分的。
可见性:当一个线程改变了一个共享的变量值,那么其他线程都是立即知道这个修改的。
有序性:在本线程内所有的操作都是有序进行的,如果一个线程观察另一个线程所有操作都是无序的。
6.先行发生原则
当A操作发生于B操作之前,那么A对于B的所有影响是可见的。比如A操作更改了值,那么B操作是可以看到的
java中天然的先发生关系
a.程序次序规则:在一个线程内按照代码顺序执行
b.管程锁定原则:一个unlock先发生于后面对同一个锁的操作
c.线程启动规则:thread对象的star()方法发生于次线程的每一个动作之前。
d.线程终止规则:线程的所有操作都在线程终止之前。
e.线程中断规则:对线程interrupt()方法先发生于被线程中断的代码检测中断事件之前。
f.对象终结规则:一个对象初始化完成先行于它发生finalize()方法的开始。
g.volatile变量规则:对一个volatile修饰的变量,在后一个读操作发生在前一个写操作之后。
i.传递性:A发生于B前,B发生于C前,那么A必定发生于C前
内容来自《深入了解JAVA虚拟机这本书》作者是周志明
如果向了解JVM可以看看这本书