JUC-JMM与volatile关键字

volatile简介及作用

volatile是JVM提供的轻量级的同步机制。volatile关键字能够保证并发编程的三大特性中的可见性,有序性。但是不能保证原子性。

保证可见性:

经过volatile修饰的变量,在本地内存中修改之后,会立即刷回主内存中。当主内存中的共享变量修改之后,其他线程的本地内存会立即同步获取到这个最新的值。

保证有序性:

通过禁止指令重排优化来保证有序性。禁止指令重排优化是通过内存屏障来实现的。

内存屏障

内存屏障就是CPU或者编译器对内存随机访问的一个同步点,使得对该点之前的操作在该点之后的操作之前。避免代码重排序。

内存屏障粗分类:

  • 读屏障:在读操作之前插入读屏障,让工作内存中的缓存失效,进而从主存中获取最新的数据。
  • 写屏障:在写操作之后插入写屏障,让工作内存中的缓存立即写入到主内存中去。

内存屏障细分类:

LoadLoad: 保证load1在load2之前执行。

StoreStore:保证store1保存在store2保存之前。

LoadStore:保证load1读取数据在store1写入数据之前。

StoreLoad:保证store保存数据在load读取数据之前。

JMM针对编译器制定的volatile重排序的规则表:

  • 当第一个操作为volatile读时,无论第二个操作是什么,都不能重排序。
  • 当第二个操作为volatile写时,无论第一个操作是什么,都不能重排。
  • 当第一个操作是volatile写时,第二个操作是读时,不能重排。

JMM在指令序列中插入屏障来禁止指令重排

  • 在volatile写操作的前面加StoreStore屏障
  • 在volatile写操作的后面加StoreLoad屏障
  • 在volatile读操作的后面加LoadLoad屏障
  • 在volatile读操作的后面加LoadStore屏障

volatile使用场景

单一赋值可以,复合赋值是禁止的。一般用来保存某个状态,判断业务是否结束。比如boolean值的flag。

总结

volatile可见性

volaile修饰的变量具有可见性。

对于写操作,本地内存中修改后,会立即刷回主存中。

对于读操作,本地内存会从主存中获取最新的值。

volatile有序性(禁止指令重排)

JMM在指令序列中通过插入内存屏障来禁止指令重排,保证有序性。

对于volatile写操作:在volatile写操作之前插入StoreStore指令,在volatile写操作之后插入StoreLoad指令来保证指令的有序。

对于volatile写操作:在volatile读操作之后插入LoadLoad指令和LoadStore指令,保证指令的有序。

参考:

1.《Java并发编程的艺术》

  1. JMM与volatile
相关推荐
唐僧洗头爱飘柔95271 个月前
(Java并发编程——JUC)常见的设计模式概念分析与多把锁使用场景!!理解线程状态转换条件!带你深入JUC!!文章全程笔记干货!!
java·设计模式·并发编程·juc·reentrantlock·顺序控制·生产者与消费者
慕木沐1 个月前
【JUC并发】cmpxchg和lock指令
后端·并发·juc·汇编指令
HelloWorld. py3 个月前
JUC-ReentrantLock 锁粒度为什么更小
java·juc
lazy★boy3 个月前
JUC学习笔记(一)
juc
lazy★boy3 个月前
JUC学习笔记(三)
juc
小小工匠4 个月前
J.U.C Review - 常见的通信工具类解析
juc·countdownlatch·exchanger·phaser·semaphore·cyclicbarrier
水w4 个月前
“线程池中线程异常后:销毁还是复用?”
java·开发语言·线程池·juc
Czi橙4 个月前
深刻理解JDK中线程池的使用
java·spring·jdk·多线程·并发编程·juc
luming-024 个月前
图文详解ThreadLocal:原理、结构与内存泄漏解析
java·开发语言·jvm·java-ee·juc
Dexu74 个月前
【Java 并发编程】(三) 从CPU缓存开始聊 volatile 底层原理
juc·java并发编程