volatile内存语义以及实现(一)

本文探讨了Java中volatile关键字的内存语义和实现原理,将其视为JMM对程序员的承诺,保证多线程环境下数据可见性。volatile特性包括数据可见性和操作原子性,通过LOCK指令确保数据同步,避免编译器和处理器重排序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

大家好,很久没有和大家分享学习知识了,今天大年初一,在这里祝大家新年快乐。

作为新年第一篇博客,我们在这里和大家分享一些关于volatile的学习知识。

首先我们知道volatile被称作是JAVA中的轻量级锁,其实个人理解这种说法并不恰当,只能是说明volatile变量具有锁的某些特性,但是不能简单的理解成锁。下面说一下本人对volatile的理解,首先一点,我并不是将voiatile当成锁来理解,我更加觉得volatile像是JMM(JAVA内存模型)对JAVA程序员的一种承诺,可以这么说,作为一个程序员,当我对我的变量使用的volatile来修饰的时候,那么JMM就保证了这个变量在多线程情况下的数据可见性,对于使用者来说,我并不需要知道,这种可见性是怎么实现的。所以volatile更像是一种承诺,类似于Serializable接口,这个接口并没有实现任何的方法,但是实现这个接口后,JVM就会对数据在数据传输时进行序列化处理,当然,这里仅仅是做类比,两者之间是完全不同的两个东西。

那么说完了个人理解,我们来说一下volatile有什么特性以及是怎么实现的:

特性一:数据可见性

对于一个volatile变量的写,总是对之后对这个变量的读可见。

特性二:操作原子性:

对于对一个volatile变量的单个读或写总是能够保证原子性,但是类似于i++这种操作,不具备操作原子性。

那么这两个特性是怎么实现的呢?

首先我们从编译的角度来说,当对一个volatile变量进行写操作时,编译器进行编译后,会在语句后面加一个LOCK指令,这个LOCK指令是汇编指令,主要做了两件事情,在解释这两件事情之前,我们先说一下线程中的数据存储。

首先在多线程情况下,每一个线程都会有自己的一个本地内存,当然这个本地内存并不是指真实内存,本地内存可能由类似于但不限于缓存这些不同的存储结构组成,而我们的真实数据存储在共享内存中,就是我们日常说的内存,那么每个线程在操作完自己的数据后首先是将自己的数据存储到本地内存中,于是每个线程都认为自己的数据是正确的,所以当线程结束,需要将本地内存中的数据刷新到共享内存中去时,如果多个线程中的本地内存数据不一致,就会造成数据冲突,这也就是多线程情况下需要进行数据同步的本质所在。

那么我们上面说的LOCK指令完成了哪两件事情呢?其一,当在汇编语句中出现LOCK信号时,线程会将自己本地内存中的数据强制性的刷新到共享内存中去;其二,LOCK信号会使缓存了共享内存地址的其他险种中的本地内存中的数据失效,当进行读操作时,强制性要求回到共享内存中进行数据读取。

可以这么理解,我们有两个线程A和B,线程A对volatile变量c进行了操作。而线程A和线程B中同时缓存了变量c在共享内存中的内存地址。那么当线程A对c进行写操作时,就会在汇编语句中出现LOCK信号,然后强制性的将c刷新到共享内存中去,并使缓存了内存地址的线程B中的数据失效。当线程B需要进行volatile变量的读取时,就会强制性要求回到共享内存中进行读取,因为本地内存数据已经失效了。通过这种方式便实现了多线程情况下的数据可见性。

其次,volatile修饰的变量会禁止某些编译器以及处理器重排序。

编译器和处理器重排序是什么意思呢?可以这么理解,其实我们的程序在某些情况下并不是按照代码顺序进行执行的,因为JVM希望在不改变程序运行结果的情况下,尽可能高的提高程序运行速度以及并发度,怎么例如我们先后对变量a和变量b进行写操作,由于变量a和b之间并不存在数据依赖,所以编译器可能会对两个语句进行重排序处理,对于重排序的知识,请参考《JAVA并发编程的艺术》,在这里并不多讲。

其实我们上面讲volatile变量的两个特性:对于一个volatile变量的写,总是对之后对这个变量的读可见。我们可以看出来如果我们允许对olatile变量的写/读重排序的话,将volatile读重排序到volatile写之前,那么久无法保证这一点特性,所以volatile变量不允许重排序。具体的重排序禁止规则如下:

是否可以重排序 第二个操作 
第一个操作普通读/写volatile读volatile写
普通变量读/写  
volatile读
volatile写 

由上表可知:当第一个操作是对volatile变量的读时,不论第二个操作是什么,都不允许重排序,当第二个操作是volatile写时,不论第一个操作是什么,都不允许重排序。这样就保证了我们上面说的第一条特性。

那么编译器和处理器是怎么被禁止重排序的呢?这个我们在之后再来分享。

谢谢各位,如有不当之处,还望多多指教。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值