中年|揭秘JMM、Synchronized、Volatile之间的关系


Volatile可以说是我们Java虚拟机给我们提供的一个轻量级的同步机制 , 与Synchronized类似 , 但是却没有它那么强大 。 关于Volatile最主要的特点呢就是它的三大特性:
保证可见性
不保证原子性
禁止指令重排
而要了解Volatile的话 , 我们就需要有JMM的基础 , 所以我们要介绍JMM的相关知识 。
【中年|揭秘JMM、Synchronized、Volatile之间的关系】1 初步了解JMM 1.1 什么是JMM呢?
JMM是Java内存模型的缩写(Java Memory Model) , 是一种逻辑的东西 , 物理上不存在的 。 可以说是一种概念或者约定 。 比如关于约定有以下的一些:
1、线程在解锁前 , 必须把共享的变量立刻刷新回主存!
2、线程在加锁前 , 必须读取主存中最新的值到工作内存(线程有自己的工作内存)中!
3、加锁和解锁是同一把锁
1.2 JMM的内存操作
JMM呢我们逻辑上可以把它分为主内存和工作内存 。 而两个内存之间也是有进行交互的 , 就是一个变量如何从主内存传输到工作内存中 , 如何把修改后的变量从工作内存回到主内存 。 关于这些操作我们主要是有八种:
lock(锁定):作用于主内存的变量 , 一个变量在同一时间只能一个线程锁定 , 该操作表示这条线程独占这个变量

unlock(解锁):作用于主内存的变量 , 表示这个变量的状态由处于锁定状态被释放 , 这样其他线程才能对该变量进行锁定
read(读取):作用于主内存变量 , 表示把一个主内存变量的值传输到线程的工作内存 , 以便随后的load操作使用
load(载入):作用于线程的工作内存的变量 , 表示把read操作从主内存中读取的变量的值放到工作内存的变量副本中(副本是相对于主内存的变量而言的)
use(使用):作用于线程的工作内存中的变量 , 表示把工作内存中的一个变量的值传递给执行引擎 , 每当虚拟机遇到一个需要使用变量的值的字节码指令时就会执行该操作
assign(赋值):作用于线程的工作内存的变量 , 表示把执行引擎返回的结果赋值给工作内存中的变量 , 每当虚拟机遇到一个给变量赋值的字节码指令时就会执行该操作
store(存储):作用于线程的工作内存中的变量 , 把工作内存中的一个变量的值传递给主内存 , 以便随后的write操作使用
write(写入):作用于主内存的变量 , 把store操作从工作内存中得到的变量的值放入主内存的变量中
在使用上的流程就是如下顺序 , 我们可以画一个图就更加清晰明了:
我的主内存有一个flag = false通过线程A来修改为true 。

中年|揭秘JMM、Synchronized、Volatile之间的关系
本文插图

但是需要注意的是 , 在使用这些指令的时候也是需要满足一些规则的:
不允许read和load、store和write操作之一单独出现 , 即不允许一个变量从主内存读取了但工作内存不接受 , 或者工作内存发起回写了但主内存不接受的情况出现 。
不允许一个线程丢弃它最近的assign操作 , 即变量在工作内存中改变了之后必须把该变化同步回主内存
不允许一个线程无原因地(没有发生过任何assign操作)把数据从线程的工作内存同步回主内存中 。
一个新的变量只能在主内存中“诞生” , 不允许在工作内存中直接使用一个未被初始化(load或assign)的变量 , 换句话说就是对一个变量实施use、store操作之前 , 必须先执行assign和load操作 。
一个变量在同一个时刻只允许一条线程对其进行lock操作 , 但lock操作可以被同一条线程重复执行多次 , 多次执行lock后 , 只有执行相同次数的unlock操作 , 变量才会被解锁 。 (也就是可重入锁的概念)
如果对一个变量执行lock操作 , 那将会清空工作内存中此变量的值 , 在执行引擎使用这个变量前 , 需要重新执行load或assign操作以初始化变量的值 。


推荐阅读