Skip to content

Latest commit

 

History

History
85 lines (27 loc) · 3.18 KB

File metadata and controls

85 lines (27 loc) · 3.18 KB

80、再看volatile关键字对原子性、可见性以及有序性的保证

volatile对原子性的保证真的是非常的有限,其实主要就是32位jvm中的long/double类型变量的赋值操作是不具备原子性的,加上volatile就可以保证原子性了

volatile boolean isRunning = true;

线程1:

Release屏障

isRunning = false;

Store屏障 => 对于之前的讲解,更进了一步,原理,没有过多的牵扯到内存屏障的一些东西,可见性和有序性,主要都是基于各种内存屏障来实现的

线程2:

Load屏障

while(isRunning) {

Acquire屏障

// 代码逻辑

}

在volatile变量写操作的前面会加入一个Release屏障,然后在之后会加入一个Store屏障,这样就可以保证volatile写跟Release屏障之前的任何读写操作都不会指令重排,然后Store屏障保证了,写完数据之后,立马会执行flush处理器缓存的操作

在volatile变量读操作的前面会加入一个Load屏障,这样就可以保证对这个变量的读取时,如果被别的处理器修改过了,必须得从其他处理器的高速缓存(或者主内存)中加载到自己本地高速缓存里,保证读到的是最新数据;

在之后会加入一个Acquire屏障,禁止volatile读操作之后的任何读写操作会跟volatile读指令重排序

跟之前讲解的volatie读写内存屏障的知识对比一下,其实你看一下是类似的意思的

那个Acquire屏障其实就是LoadLoad屏障 + LoadStore屏障,Release屏障其实就是StoreLoad屏障 + StoreStore屏障

好像有点不太一样,对吧?

其实不要对内存屏障这个东西太较真,因为说句实话,不同版本的JVM,不同的底层硬件,都可能会导致加的内存屏障有一些区别,所以这个本来就没完全一致的。你只要知道内存屏障是如何保证volatile的可见性和有序性的就可以了

看各种并发相关的书和文章,对内存屏障到底是加的什么屏障,莫衷一是,没有任何一个官方权威的说法,因为这个内存屏障太底层了,底层到了涉及到了硬件,硬件不同对内存屏障的实现是不一样的

内存屏障这个东西,大概来说,其实就是大概的给你说一下这个意思,尤其是Release屏障,Store屏障和Load屏障还好理解一些,比较简单,Acqurie屏障,莫衷一是,我也没法给你一个官方的定论

具体底层的硬件实现

如果你一定 要杠到底,到底加的准确的屏障是什么?到底是如何跟上下的指令避免重排的,你自己去研究吧。我之前看过很多的资料,做过很多的研究,硬件对这个东西的实现和承诺,莫衷一是,没有标准和官方定论。

两点:volatile读写前后会加屏障,避免跟前后的读写操作发生指令重排

volatile和synchronized保证可见性和有序性,原来都是通过各种内存屏障来实现的,因为加了内存屏障,就会有一些特殊的指令和实现,就可以保证可见性和有序性了,有序性在几个阶段的指令重排的问题

内存屏障对应的底层的一些基本的硬件级别的原理,也都讲清楚了