线程间通信----volatile

volatile的特性

可见性和原子性。

volatile写-读建立的happens-before关系

从内存语义的角度来说,volatile的 写-读 与 锁的释放-获取 有相同的内存效果;volatile 写 和 锁的释放 有相同的内存语义;volatile 读 与 锁的获取 有相同的内存语义。

根据hanppens-before规则,锁的释放必须对随后这个锁的获取可见,所以,volatile的写对读可见。

volatile写-读的内存语义

写一个volatile变量时,JMM会把线程对应对本地内存中的共享变量值刷新到主内存。

读一个volatile变量时,JMM会把该线程对应的本地内存置为无效。线程接下来将从主内存中读取共享变量。

线程A写一个volatile变量,实质上是线程A向接下来将要读这个volatile变量的某个线程发出了(其对共享变量所做修改的)消息。

线程B读一个volatile变量,实质上是线程B接收了之前某个线程发出的(在写这个volatile变量之前对共享变量所做修改的)消息。

线程A写一个volatile变量,随后线程B读这个volatile变量,这个过程实质上是线程A通过主内存向线程B发送消息。

volatile内存语义的实现

 

当第二个操作是volatile写时,不管第一个操作是什么,都不能重排序。这个规则确保volatile写之前的操作不会被编译器重排序到volatile写之后。

当第一个操作是volatile读时,不管第二个操作是什么,都不能重排序。这个规则确保volatile读之后的操作不会被编译器重排序到volatile读之前。

当第一个操作是volatile写,第二个操作是volatile读时,不能重排序。

 

为了实现volatile的内存语义,编译器在生成字节码时,会在指令序列中插入内存屏障来禁止特定类型的处理器重排序。对于编译器来说,发现一个最优布置来最小化插入屏障的总数几乎不可能。为此,JMM采取保守策略。下面是基于保守策略的JMM内存屏障插入策略。

 

在每个volatile写操作的前面插入一个StoreStore屏障。

在每个volatile写操作的后面插入一个StoreLoad屏障。

在每个volatile读操作的后面插入一个LoadLoad屏障。

在每个volatile读操作的后面插入一个LoadStore屏障。

posted @ 2020-09-07 17:00  kylinmac  阅读(164)  评论(0)    收藏  举报