您的位置:首页 > 其它

volatile和锁的内存语义与实现

2017-03-28 14:43 127 查看

1.volatile的内存语义与实现

1.1 volatile写读的内存语义

在介绍锁的内存语义之前,我们先简单介绍一下volatile写读的内存语义:

当写一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量值刷新到主内存中。

当读一个volatile变量时,JMM会把该线程对应的本地内存置为无效,线程接下来将从主内存中读取共享变量

这两条保证了volatile能够达到它的即时可见的特性。

那JMM如何能够保证volatile实现其内存语义的,简单来说就是通过内存屏障。如果看过volatile变量汇编后的指令代码就会在代码中发现一句:

lock add1 $0x0

它的简单含义就是要把工作内存中的共享变量值刷新到主内存中,相当于加入内存屏障。

1.2 volatile有序的内存语义

volatile的另一个特性是禁止指令重排序,这里的内存语义我们可以总结为:

volatile读之后 的操作不会被重排序到 volatile读之前

volatile写之前 的操作不会被重排序到 volatile写之后

先volatile写–后volatile读,不可重排序

JMM通过插入内存屏障来实现以上语义,实质上有四种内存屏障策略:

volatile写操作前插入StoreStore屏障

volatile写操作后插入StoreLoad屏障

volatile读操作前插入LoadLoad屏障

volatile读操作后插入LoadStore屏障

其中StoreLoad屏障是全能型屏障,可以完成其他3个屏障的功能。所以它被大部分CPU支持。不同CPU有着不同的重排序规则,但是这一套JMM屏障策略可以完成所有类型CPU下的volatile语义。例如对于x86的CPU,它本身只支持写-读操作的重排序,对读-读,读-写,写-写操作的重排序都不支持;那么我们只需要加入StoreLoad屏障来避免写-读操作的重排序即可实现volatile语义。

2.锁的内存语义与实现

理解了volatile的内存语义,锁的内存语义就会好理解了。

当线程获取锁时,JMM会把线程对应的本地内存置为无效,然后临界区的代码从主存中读入共享变量到工作内存。

当线程释放锁时,JMM会把该线程对应的本地内存中的共享变量刷新到主内存中。

看完上面锁的内存语义,是不是感觉和volatile的内存语义很相像。对比锁和volatile的内存语义:

锁的获取和volatile的读有相同的内存语义

锁的释放和volatile的写有相同的内存语义

那锁的内存语义是如何实现的?

下一篇《ReentrantLock的源代码解析和锁的内存语义实现》将结合jdk源码进行分析。

参考:

特别感谢《Java并发编程的艺术》

http://ifeve.com/volatile/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: