volatile关键字的作用

volatile 关键字的作用

引言:笔试碰到volatile关键字是否可以保证线程安全,因此记录下volatile到底是一个什么。

1. volatile为什么不能保证多线程安全

1.1 满足多线程安全的三要素:可见性、顺序性、原子性。
1.2 volatile只能满足可见性、顺序性。

2. volatile 语义是什么

volatile 是基于内存屏障来实现的,内存屏障是一个cpu指令。

2.1 第一保证特定操作的执行顺序
由于编译器和处理器能执行指令重排优化,如果在指令间插入一条内存屏障,则会告诉编译器和CPU,不管什么指令都不能和这条内存屏障指令重排序。也就是通过内存屏障禁止在内存屏障前后的指令执行重排序优化。
2.1 第二保证某些变量的内存可见性
内存屏障的另一个作用就是强制刷出各种CPU的缓存数据。对volatile变量进行写操作时,会在写操作后加入一条写屏障指令,将工作内存中的共享变量值刷回到主内存(发送事件,表明原有线程中的变量值全都作废,从新去主内存拉取);volatile变量进行读操作时,会在读操作前加入一条写屏障指令,将主内存中的变量读取到工作内存中。

3. volatile 类型变量的特殊规则

3.1 关键字volatile可以说是Java虚拟机提供的最轻量级的同步机制(但不能保证线程安全)。
3.2 当一个变量被定义成volatile之后,它将具备两项特性:第一个语义是保证此变量对所有线程的可见性, 这里的“可见性”是指当一条线程修改了这个变量的值,新值对于其他线程来说是可以立即得知的。而普通变量并不能做到这一点,普通变量的值在线程间传递时均需要通过主内存来完成。比如,线程A修改一个普通变量的值,然后向主内存进行回写,另外一条线程B在线程A回写完成了之后再对主内存进行读取操作,新变量值才会对线程B可见。第二个语义是禁止指令重排序优化,从而避免了多线程环境下程序出现乱序执行的现象。
3.3 Java内存模型要求lock、unlock、read、load、assign、use、store、write这八种操作都具有原子性,但是对于64位的数据类型(long和double),在模型中特别定义了一条宽松的规定:允许虚拟机将没有被volatile修饰的64位数据的读写操作划分为两次32位的操作来进行,即允许虚拟机实现自行选择是否要保证64位数据类型的load、store、read和write这四个操作的原子性,这就是所谓的 “long和double的非原子性协定”(Non-Atomic Treatment of double and long Variables)
如果有多个线程共享一个并未声明为volatile的long或double类型的变量,并且同时对它们进行读取和修改操作,那么某些线程可能会读取到一个既不是原值,也不是其他线程修改值的代表了“半个变量”的数值。不过这种读取到“半个变量”的情况是非常罕见的,经过实际测试,在目前主流平台下商用的64位Java虚拟机中并不会出现非原子性访问行为,但是对于32位的Java虚拟机,譬如比较常用的32位x86平台下的HotSpot虚拟机,对long类型的数据确实存在非原子性访问的风险。

4. Java内存模型简述

4.1 用来屏蔽各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到一致的内存访问效果。
4.2 Java内存模型规定:第一, 所有的变量都存储在主内存中;第二,每条线程还有自己的工作内存,线程的工作内存中保存了被该线程使用的变量的主内存副本,线程对变量的所有操作(读取、赋值等)都必须在工作内存中进行,而不能直接读写主内存中的数据; 第三,不同的线程之间也无法直接访问对方工作内存中的变量,线程间变量值的传递均需要通过主内存来完成。
4.3 线程、主内存、工作内存三者的交互关系如图:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值