Volatile关键字在内存模型中的特殊规则

当一个变量被Volatile关键字修饰后,便具有两种特性,一是保证变量对所有线程的可见性,二是禁止指令重排序优化。

可加性是指一个线程对变量的值进行修改后,其他加载了该变量线程能立即得知这个变化,普通变量做不到这一点,普通变量的值在线程中传递必须依靠主内存来完成,普通变量与volatile变量的区别是,volatile的特殊规则保证了新值能立即同步到主内存,以及每次使用前立即从主内存刷新。volatile变量在各线程的工作内存中不存在一致性问题,因为各线程每次使用钱都会先刷新。但是Java里面的运算并非原子操作,导致volatile变量的运算在并发下一样是不安全的。因此在不符合以下两个情况时,依然需要使用加锁的方式来保证原子性。

  1. 运算结果不依赖变量的当前值,或者确保只有单一的线程修改变量的值
  2. 变量不需要于状态变量共同参与不变约束

禁止指令重排序优化是指,普通变量仅仅会保证在该方法的执行过程中所有依赖赋值结果的的地方都能获得正确的结果,而不能保证变量赋值的顺序于代码顺序一致,这就是所谓的线程内表现为串行的语义,是由于指令重排序优化导致的。但是被volatile修饰和被形成内存屏障,便禁止了指令重排序优化,使得指令的执行顺序按照代码顺序执行。

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

  • 只有当线程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修饰的变量不会被指令重排序优化,保证代码的执行顺序与程序的顺序相同)。

大多数场景下volatile的总开销仍然要比锁低,我们在volatile与锁之中选择的唯一依据仅仅是volatile的语义能否满足使用场景的需求

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值