Java并发编程的艺术学习笔记(三) Java内存模型(四)

3.4 volatile内存语义

3.4.1 volatile的特性

一个volatile变量的单个读写操作,与一个普通变量的读写操作都是使用同一个锁来同步,他们之间的执行效果相同。

锁的happens-before规则保证释放锁和获取锁的两个线程之间的内存可见性,意味着对一个volatile变量的读,总是能看到(任意线程)对这个volatile变量最后的写入。(可见性)

即使是64位long或double型变量,只要是volatile变量,读写操作就具有原子性。但是多个volatile操作或类似于volatile++这种复合操作,就不具有原子性。(原子性)

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

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

3.4.3 volatile写——读的内存语义

Java并发编程的艺术学习笔记(三) Java内存模型(四)_第1张图片

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

当读一个volatile变量时,JMM会把该线程对应的本地内存置为无效

·线程A写一个volatile变量,实质上是线程A向接下来将要读这个volatile变量的某个线程发出了(其对共享变量所做修改的)消息。
·线程B读一个volatile变量,实质上是线程B接收了之前某个线程发出的(在写这个volatile变量之前对共享变量所做修改的)消息。
·线程A写一个volatile变量,随后线程B读这个volatile变量,这个过程实质上是线程A通过 主内存向线程B发送消息。

Java并发编程的艺术学习笔记(三) Java内存模型(四)_第2张图片

3.4.4 volatile内存语义的实现

为了实现volatile内存语义,JMM会限制编译器重排序和处理器重排序。

Java并发编程的艺术学习笔记(三) Java内存模型(四)_第3张图片

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

为了实现volatile内存语义,编译器在生成字节码时,会在指令序列中插入内存屏障来禁止特定类型的处理器重排序。

Java并发编程的艺术学习笔记(三) Java内存模型(四)_第4张图片

3.4.5 JSR-133为什么要增强volatile的内存语义

在旧的内存模型中,volatile的写-读没有锁的释放-获所具有的内存语义。为了提供 一种比锁更轻量级的线程之间通信的机制,JSR-133专家组决定增强volatile的内存语义:严格 限制编译器和处理器对volatile变量与普通变量的重排序,确保volatile的写-读和锁的释放-获 取具有相同的内存语义。从编译器重排序规则和处理器内存屏障插入策略来看,只要volatile 变量与普通变量之间的重排序可能会破坏volatile的内存语义,这种重排序就会被编译器重排
序规则和处理器内存屏障插入策略禁止。
 

 

你可能感兴趣的:(并发编程,Java)