java volatitl_JVM 之 volatitle 关键字

1、Java 内存模型

主内存:类比Jvm 模型 相当于堆;

工作内存:线程独有的内存,类比处理器的高速缓存;

线程的「工作内存」保存了被当前线程使用到的变量的主内存的「副本拷贝」,线程对变量所有的操作(读取、赋值)都必须在「工作内存中」完成,不能直接读写主内存中的变量;不同的线程之间不能「直接」相互访问对方工作内存中的变量,线程之间的值传递需要通过主内存来完成;

线程-工作内存-主内存之间的关系如下:

2、内存间的交互操作

工作内存和主内存的交互主要这8个操作lock(锁定):作用于主内存的变量,它把变量标识为线程独占状态;

unlock(解锁):作用于主内存的变量,它把一个处于锁定状态的变量释放出来,只有释放出来的变量才能被其他线程锁定;

read(读取):作用于主内存的变量,它把一个变量的值从主内存传输到工作内存中,便于下一个(load)操作;

load(载入):作用于工作内存的变量,它把read操作从主内存中得到的变量值放入到工作内存中的变量副本中;

use(使用):作用于工作内存的变量,它把工作内存中的变量的值传递给执行引擎;

assign(赋值):作用于工作内存的变量,它把一个执行引擎接收到的值赋给工作内存的变量;

store(存储):作用于工作内存变量,它把工作内存中的变量值传送到主内存中,便于下一个操作(write)使用;

write(写入):作用于主内存的变量,它把store操作从工作内存中得到的值放入主内存变量中;

操作规则不允许 read和load ,store和write操作之一单独出现;

不允许一个线程丢弃它最近的assign操作,变量在工作内存中改变了之后必须把变化同步到主内存中;

不允许一个线程无原因的(不经过任何assign操作)把数据从工作内存同步回主内存中;

一个新的变量必须从主内存中“诞生”;

一个变量在同一时刻只允许一条线程对其lock操作,但是可以被lock多次,但是必须执行相同次数的unlock操作才可以被解锁;

如果对一个变量lock操作,那么会清空工作内存中此变量的值,在执行引擎使用这个变量前,需要重新执行load或assign操作初始化变量的值;

一个变量未执行lock,不允许对它执行unlock操作,也不允许去unlock一个被其他线程lock的对象;

对一个变量执行unlock前,必须将此变量的值同步回主内存中;

volatitle

一、保证可见性,并不能保证操作的原子性,使用volatitle需要满足下面的条件运算结果并不依赖变量的当前值,或者能确保只有单一的线程修改线程的变量值;

变量不需要与其他的状态变量共同参与不变约束;(个人理解是没有其他的变量 即 n=1,n=m+1这种操作,而不是n=n+1,这种n不确定状态的操作)

二、禁止指令重排

Java内存模型中对volatile变量定义的特殊规则。

假定T表示一个线程,V和W分别表示两个volatile型变量,那么在进行read、load、use、assign、store和write操作时需要满足如下规则:

只有当线程T对变量V执行的前一个动作是load的时候,线程T才能对变量V执行use动作;并且,只有当线程T对变量V执行的后一个动作是use的时候,线程T才能对变量V执行load动作。线程T对变量V的use动作可以认为是和线程T对变量V的load、read动作相关联,必须连续一起出现;(这条规则要求在工作内存中,每次使用V前都必须先从主内存刷新最新的值,用于保证能看见其他线程对变量V所做的修改后的值)。

只有当线程T对变量V执行的前一个动作是assign的时候,线程T才能对变量V执行store动作;并且,只有当线程T对变量V执行的后一个动作是store的时候,线程T才能对变量V执行assign动作。线程T对变量V的assign动作可以认为是和线程T对变量V的store、write动作相关联,必须连续一起出现(这条规则要求在工作内存中,每次修改V后都必须立刻同步回主内存中,用于保证其他线程可以看到自己对变量V所做的修改)。

假定动作A是线程T对变量V实施的use或assign动作,假定动作F是和动作A相关联的load或store动作,假定动作P是和动作F相应的对变量V的read或write动作;类似的,假定动作B是线程T对变量W实施的use或assign动作,假定动作G是和动作B相关联的load或store动作,假定动作Q是和动作G相应的对变量W的read或write动作。如果A先于B,那么P先于Q(这条规则要求volatile修饰的变量不会被指令重排序优化,保证代码的执行顺序与程序的顺序相同)。

JMM基于保守策略的JMM内存屏障插入策略:

1.在每个volatile写操作的前面插入一个StoreStore屏障

2.在每个volatile写操作的后面插入一个SotreLoad屏障

3.在每个volatile读操作的后面插入一个LoadLoad屏障

4.在每个volatile读操作的后面插入一个LoadStore屏障

实现规则

JMM对读写的重排序有以下规则,纵轴为操作1,横轴为操作2:

从表中可以看出,在第一个操作为volatile读的时候,其后的所有变量读写操作都不会重排序到前面。

在第二个操作为volatile读的时候,其之前的所有volatile读写操作都已完成,

在第一个操作为volatile写的时候,其后的volatile变量读写操作都不会重排序到前面。

可以得出以下内存屏障表格

根据JMM规则,结合内存屏障的相关分析,可以得出以下保守策略:volatile读之后,会添加LoadLoad内存屏障。

volatile读之后,会添加LoadStore内存屏障。

volatile写之前,会添加StoreStore内存屏障。

volatile写之后,会添加StoreLoad型内存屏障。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值