内存语义
内存语义指的是:
在多线程或处理器中用来控制存取共享内存位置,或者说是在更高层次上共享变量的处理逻辑。
volatile的happens-before原则
volatile变量原则:对一个volatile域的写,happens-before于任意后续对这个volatile域的读。
volatile的内存语义
volatile的内存语义即是用来保证volatile的happens-before原则。
-
volatile写:当写一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量值刷新到主内存。
-
volatile读:当读一个volatile变量时,JMM会把该线程对应的本地内存置为无效。线程接下来将从主内存中读取共享变量。
-
线程A写一个volatile变量,实质上是线程A向接下来将要读这个volatile变量的某个线程发出了(其对共享变量所做修改的)消息。
-
线程B读一个volatile变量,实质上是线程B接收了之前某个线程发出的(在写这个volatile变量之前对共享变量所做修改的)消息。
-
线程A写一个 volatile变量,随后线程B读取这个volatile变量,这个过程实质上是线程A通过主内存向线程B发送消息。
volatile内存语义的实现
为了实现volatile的内存语义,编译器在生成字节码时,会在指令序列中插入内存屏障来禁止特定类型的处理器重排序。
内存屏障是一种barrier指令类型,它导致CPU或编译器对barrier指令前后发出的内存操作执行顺序约束。也就是说,在barrier之前的内存操作保证在barrier之后的内存操作之前执行。
内存屏障有以下4种:
- LoadLoad屏障:对于这样的语句Load1; LoadLoad; Load2,在Load2及后续读取操作要读取的数据被访问前,保证Load1要读取的数据被读取完毕。
- StoreStore屏障:对于这样的语句Store1; StoreStore; Store2,在Store2及后续写入操作执行前,保证Store1的写入操作对其它处理器可见。
- LoadStore屏障:对于这样的语句Load1; LoadStore; Store2,在Store2及后续写入操作被刷出前,保证Load1要读取的数据被读取完毕。
- StoreLoad屏障:对于这样的语句Store1; StoreLoad; Load2,在Load2及后续所有读取操作执行前,保证Store1的写入对所有处理器可见。它的开销是四种屏障中最大的。 在大多数处理器的实现中,这个屏障是个万能屏障,兼具其它三种内存屏障的功能。
为了实现volatile内存语义,Java编译器会这样使用内存屏障:
内存屏障 ---实现---> 内存语义 ---保证---> happens-before原则
网友评论