编程语言-Java系列

5、Volitle关键字详解

2020-05-21  本文已影响0人  火山_6c7b

1.volitle特性及解释

可见性

有序性

2. volitle特性的实现原理

  简单说volitle是通过内存屏障即读屏障和写屏障来实现可见性和有序性,因为内存屏障禁止强制前后指令按序执行,并且强制读取和更新主存数据。

2.1 内存屏障

  内存屏障(memory barrier) 是一个CPU指令。基本上,它是这样一条指令: a) 确保一些特定操作执行的顺序; b) 影响一些数据的可见性(可能是某些指令执行后的结果)。编译器和CPU可以在保证输出结果一样的情况下对指令重排序,使性能得到优化。插入一个内存屏障, 相当于告诉CPU和编译器先于这个命令的必须先执行,后于这个命令的必须后执行。内存屏障另一个作用是强制更新一次不同CPU的缓存。例如,一个写屏障会 把这个屏障前写入的数据刷新到缓存,这样任何试图读取该数据的线程将得到最新值,而不用考虑到底是被哪个cpu核心或者哪颗CPU执行的。

2.2 Load Barrier 和 Store Barrier即读屏障和写屏障

内存屏障有两个作用:

2.3 volitle中的内存屏障

2.4 final语义中的内存屏障

2.5 java中应用

3.happens-before原则

下面就来具体介绍下happens-before原则(先行发生原则):
程序次序规则:一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作

4. volatile和缓存一致性协议MESI的关系

  首先明确二者并无关系,volatile是java语言层面给出的保证,MSEI协议是多核cpu保证cache一致性,volatile和MESI差着好几层抽象,中间会经历java编译器,java虚拟机和JIT,操作系统,CPU核心。

  对于x86的体系结构,voltile变量的访问代码会被java编译器生成不乱序的,带有lock指令前缀的机器码。而lock的实现还要区分,这个数据在不在CPU核心的专有缓存中(一般是指L1/L2/L3)。如果在,MESI才有用武之地。如果不满足就会要用其他手段。而这些手段是虚拟机开发者,以及操作系统开发者需要考虑的问题。简而言之,CPU里的缓存,buffer,queue有很多种。MESI只能在一种情况下解决核心专有Cache之间不一致的问题。此外,如果有些CPU不支持MESI协议,那么必须用其他办法来实现等价的效果,比如总是用锁总线的方式,或者明确的fence指令来保证volatile想达到的目标。

  mesi只是保证了L1-3 的cache之间的可见性,但是cpu和L1之间
还有像storebuffer之类的缓存,而volatile规范保证了对它修饰的变量的写指令会使得当前cpu所有缓存写到被mesi保证可见性的L1-3cache中。(具体的实现,以X86体系为例,volatile会被JVM生成带lock前缀的指令)。

4.1 Volatile是如何保证可见性的

  加入volatile关键字时,会多出一个lock前缀指令,lock前缀指令实际上相当于一个内存屏障,它有三个功能:

4.2 缓存一致性协议

缓存一致性协议有多种,但是日常处理的大多数计算机设备都属于”嗅探(snooping)”协议,它的基本思想是:

IA-32手册对lock指令作用的描述,可以得出lock指令的作用:

上一篇 下一篇

猜你喜欢

热点阅读