java服务器租用_Java内存模型与volatile

本文详细探讨了Java内存模型中主内存与工作内存之间的交互协议,包括8种关键操作及其原子性。重点讲解了volatile关键字的作用,如何保证可见性和禁止指令重排序,并介绍了内存屏障在其中的角色,如StoreStore、LoadLoad等。此外,文章还讨论了volatile在不同处理器上的优化策略。
摘要由CSDN通过智能技术生成

065c4b2889eeb192081726fb32f1e11d.jpg

内存间的交互操作[2]

关于主内存和工作内存之间的具体交互协议,即一个变量如何从主内存拷贝到工作内存、如果从工作内存拷贝到主内存这一类的实现细节,Java内存模型中定义了以下8种操作。每个操作必须是原子性的、不可再分的(double和long除外,因为double和long是64位,在32位的机器中需要划分为两次32位的操作来实现)

lock & unlock (锁)lock:作用于主内存中的变量,它把一个变量标识为一条线程独占的状态

unlock:作用于主内存中的变量,它把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定

read & load & use(主内存到工作内存)read:作用于主内存中的变量,它把一个变量中的值从主内存传输到线程的工作内存中,以便随后的load动作使用

load:作用与工作内存的变量,它把read操作从主内存中得到的变量放入工作内存的变量副本中

use:作用于工作内存中的变量,它把工作内存中一个变量的值传递给执行引擎,每当虚拟机遇到一个需要使用的变量的值的字节码指令时执行这个操作

assign & store & write(工作内存到主内存)assign:作用于工作内存的变量,它把一个从执行引擎接收的值赋给工作内存中的变量,每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作

store:作用于工作内存中的变量,它把工作内存中一个变量的值传递到主内存中,以便随后的write操作使用

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

volatile

既然了解了Java内存模型,那就可以很好地理解volatile关键字了,我们小学二年级就知道volatile关键字的两个重要作用是保证可见性和禁止指令重排序

保证可见性

这里需要注意的是,保证可见性不能得出线程安全,在并发操作中,多个线程同时对volatile修饰的变量进行读写,依然会是线程不安全的。

这里的可见性是指“当一条线程修改这个变量的值,新值对于其他线程来说是马上得知的”。普通变量不具备这一特征的,因为普通变量被修改之后,需要回写到主内存,其他线程从主内存读取之后才会感知到变量的变化。

当写一个vilotile修饰的变量的时候,JMM都会把该线程对应的本地内存中的共享便来嗯刷新到主内存中;当读一个volatile修饰的变量时,JMM会把该线程对应的本地内存置为无效,线程接下来将从主内存中读取共享变量

禁止重排序

java语言规范JVM线程内部维持顺序化语义,即只要程序的最终结果与它顺序化情况的结果相等,那么指令的执行顺序可以与代码逻辑不一致,这个过程就叫做指令重排序.而vilotile关键字可以禁止指令重排序,具体规则如下

下面的表是volatile有关的禁止指令重排的行为[3]:

dc1d10bde6ad7554d98157fa31fee100.jpg

这里,禁止指令重排序是通过内存屏障进行实现的,关于内存屏障,可以参考内存屏障

jvm中有4种内存屏障[4],分别是:LoadLoad屏障:对于这样的语句Load1; LoadLoad; Load2,在Load2及后续读取操作要读取的数据被访问前,保证Load1要读取的数据被读取完毕。StoreStore屏障:对于这样的语句Store1; StoreStore; Store2,在Store2及后续写入操作执行前,保证Store1的写入操作对其它处理器可见。

LoadStore屏障:对于这样的语句Load1; LoadStore; Store2,在Store2及后续写入操作被刷出前,保证Load1要读取的数据被读取完毕。

StoreLoad屏障:对于这样的语句Store1; StoreLoad; Load2,在Load2及后续所有读取操作执行前,保证Store1的写入对所有处理器可见。它的开销是四种屏障中最大的。在大多数处理器的实现中,这个屏障是个万能屏障,兼具其它三种内存屏障的功能

JMM的内存屏障插入策略为保守策略,具体为:在每个volatile写操作之前插入一个StoreStore屏障,之后插入一个StoreLoad屏障

在每个volatile读操作之后插入一个为LoadLoad屏障和一个LoadStore屏障

如下图[5]

577edd29abdb5548ea114fe309911868.jpg

6c0a62b5f2cb95f41efdbb648f0b48f2.jpg

这里的优化是针对任意处理器平台而言,实际上,不同处理器有不同“松紧度”的内存模型,内存屏障的插入还可以根据具体的处理器内存模型继续优化。

以x86处理器为例,除了最后的StoreLoad屏障外,其他屏障都会被忽略。因为x86处理器仅会对写-读操作进行指令重排序,不会对读-读、读-写、写-写操作进行重排序。这里同时意味着,volatile的写比读开销大得多,因为会插入一个StoreLoad屏障[6]。

参考^https://blog.csdn.net/javazejian/article/details/72772461

^《深入理解JVM虚拟机》(第3版)

^https://juejin.cn/post/6844903865343541261

^https://www.jianshu.com/p/2ab5e3d7e510

^https://juejin.cn/post/6844903601064640525

^《Java并发编程的艺术》

标签:

相关推荐

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值