我们日常开发写代码,一定会和变量打交道,变量和控制逻辑,一起组成了我们写的程序
变量存在哪里呢?咱们知道,就存在内存里
不同的编程语言,不同的机器,有着不同的内存模型
作为一个Java选手,我们在上一篇初步学习了Java内存模型
今天就来一起简单看看Java内存模型的具体操作
并且通过这些操作,揭开 volatile 变量的秘密,彻底明白 volatile 变量为何具有 立即可见的 特性
8个操作
实际上,Java内存模型中,定义了8种操作,来完成变量在不同位置的存储,读取
正是本篇要讲的8种操作,将我们上文所说的JMM的两个区域(工作内存,主内存)给真正联系了起来
它们分别是:
- lock
- unlock
- read
- load
- use
- assign
- store
- write
看起来有些多对吗?
编哥给你来一张图,咱们就能大致记住
如图所示
主内存那里,发生的是变量的 lock, unlock;变量就像箱子,unlock开箱才能用,用好了就 lock 起来
read 和 write ,顾名思义,就是发生在 主内存和工作内存之间的动作啦
工作内存里面的变量(实际上就是主内存的变量的副本),则有 load 和 store 两个操作可以发生
我们在 read 变量的真身 之后就可以 load 变量 到工作内存的副本中
副本 store 之后就能 write 到主内存里面的真身
再说说 use 和 assign:
我们知道,一个方法里,对变量的各种操作,运算,都实际上是执行引擎(对应硬件上的cpu)在工作
执行引擎 正是通过 use, assign 这两个操作完成和工作内存(对应硬件上的缓存)的交互
从图也可以看到,变量(也就是数据)的流向,编哥已经为你标明啦,相信这8个操作,你再也不会懵圈啦
对 volatile 变量的理解
知道了这些操作的定义,对我们平常开发有啥用呢?
比如,你将会对 volatile 变量的理解,更上一层楼
我们都知道 volatile 的变量,能保证对所有线程可见,也就是说,一个线程修改了这个 volatile 变量,其他线程立刻就看见啦
为啥能立刻看到呢?
就是因为JMM里面对于 volatile 变量的操作有特殊规则
对一个 volatile 变量,前一个动作是 load,接下来才能有 use 动作;而且只有当后一个动作是 use 时,线程才能对变量执行 load 动作
咱们做个对比,普通变量则没有这个规则, 也就是说,普通变量的 读取使用,可以不用发生 load, 就能用,这就导致了我们用的可能不是主内存里面,最新的值
上述规则,实际上是让这 read, load, use 三个动作紧挨着执行, 从而完成了一次 变量从主内存的读取(因为read动作就是发生在主内存的动作)
同理,对于写入操作, assign, store, write, 三个动作,对于 普通变量可能不会连着执行,可能只执行 assign, store, 而没有及时 write(写到主内存)
对于 volatile 变量 则是捆绑在一起执行,这就导致了,volatile 变量 的更新,立刻会反馈到主内存。而其他线程再访问这个 volatile 变量,依据 read, load, use 三个动作紧挨着执行 的规则,也会得到最新的值,而非旧值
现在你知道了为啥 volatile 变量 的 可见性 是如何保证了的吧