欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java内存模型-内存间的交互

程序员文章站 2022-03-11 20:15:05
...
3.内存间的交互操作

看到这块,小伙伴是否有这么一个疑问?不同的工作内存缓存了主内存中相同的数据,那么是否有类似于 MESI 这样的协议来保证数据一致性了?

我们先来看下内存间的交互操作吧.

内存间的交互是数据从主内存拷贝到工作内存,然后从工作内存同步会主内存的具体实现细节.

Java 内存模型定义了 8 中操作来完成,虚拟机实现时必须保证这 8 中操作都是原子操作(对于 double 和 long 型变量来说,
load、store、read 和 write 允许有例外).

(1)lock: 作用与主内存的变量,它把一个变量标识变为一个线程独占的状态.
(2)unlock: 作用于主内存的变量,解锁,只有解锁完后,其他线程才能锁定.
(3)read: 作用于主内存,把一个变量的值从主内存传入到工作内存中,以便随后的 load 动作使用(类似于实参).
(4)load: 作用于工作内存中的变量,它把 read 操作从主内存中得到的值放入工作内存的变量副本中(类似于形参).
(5)use: 作用于工作内存的变量,它把工作内存中的一个变量值传递给执行引擎,每当虚拟机遇到一个需要使用到变量的值的字节码指令时将会执行
这个操作.
(6)assign: 作用于工作内存的变量,它把一个从执行引擎接收到的值赋给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码指令时执行
这个操作.
(7)store: 作用于工作内存的变量,它把工作内存中一个变量的值传到主内存中,以便随后的 write 操作使用.
(8)write: 作用于主内存的变量,它把 store 操作从工作内存得到的变量的值放入主内存的变量中.

作用于主内存的操作:lock/unlock、read/write
作用于工作内存的操作:load/use/assign/store

对 lock/unlock 的分析:
在 JVM 中,并没有把 lock/unlock 直接开放给用户,而是提供了更高级别的 monitorenter/monitorexit 来间接操作 lock/unlock,
而 monitorenter/monitorexit 又和 synchronized 相关联. 我们知道 synchronized 在释放锁的时候,会将cache 中的值同步会主存,
这一点和 unlock 规则对应. 而 lock 只能被一个线程锁定,且对同一个线程可重入锁定.


注意:
(1)JMM 要求 read 和 load 操作以及 store 和 write 操作必须按照顺序执行(不一定连续执行).
(2)read 和 load、store 和 write 操作必须成对出现.
(3)不允许一个线程丢弃它的最近 assign 操作,即变量在工作内存中改变了之后必须把该变化同步回主内存(这里没有说立即同步喔,所以我们
会遇到多线程累加某一个变量的值100次,最后可能结果不到200).
(4)不允许一个线程无原因地(没有发生过任何 assign 操作)把数据从线程的工作内存同步回主内存中.
(5)一个新的变量只能在主内存中诞生,不允许在工作内存中直接使用一个未被初始化(load或assign)的变量,换句话说,就是对一个变量实施
use、store 操作之前,必须先执行过了 assign 和 load 操作(对应java语法规则是变量必须初始化后才能使用).
(6)一个变量在同一时刻只允许一条线程对齐进行lock操作,但lock操作可以被同一条线程重复执行多次,多次lock后,只有执行相同次数的unlock
操作,变量才会被解锁(对照 synchronized 分析).
(7)如果对一个变量执行lock操作,那将会清空工作内存中此变量的值,在执行引擎使用这个变量前,需要重新执行load或assign操作初始化
变量的值.
(8)对一个变量执行unlock操作之前,必须先把此变量同步回主内存中(执行 store、write 操作).

lock:当线程释放锁时,JMM会把该线程对应的本地内存中的共享变量刷新到主内存中

unlock:当线程获取锁时,JMM会把该线程对应的本地内存置为无效。从而使得被监视器保护的临界区代码必须从主内存中读取共享变量