为什么volatile保证不了线程安全

为什么volatile保证不了线程安全

首先要知道,想要线程安全必须保证 原子性可见性有序性
首先要了解的是, Volatile 禁止指令重排序(有序性),保证内存可见性问题,对 变量单个操作保证原子性, 那么它为什么不能保证线程安全呢?
💡 下面首先会单独介绍什么是对变量单个操作保证原子性

概念普及

JMM规定了内存主要划分为主内存和工作内存两种。每个线程都有一个自己的工作内存, 对变量的操作都是在缓存中进行的, 然后再将修改后的值返回到主存中,Java内存模型规定了所有的变量都存储在主内存(Main Memory)中 ,每条线程 还有自己的工作内存(Working Memory),线程的工作内存中保存了被该线程使用的变量的主内存副本,线程对变量的所有操作(读取、赋值等)都必须在工作内存中进行,而不能直接读写主内存中的数据。不同的线程之间也无法直接访问对方工作内存中的变 量,线程间变量值的传递均需要通过主内存来完成,线程、主内存、工作内存三者的交互关系如图:

线程、主内存、工作内存三者的交互关系

一个变量如何从主内存拷贝到工作内存、如何从 工作内存同步回主内存这一类的实现细节,Java内存模型中定义了以下8种操作来完成:
JMM8种操作

举个小小的例子:

如果我们在代码中对一个对象重新赋值,int race = 0 ,那么随后就要将新的值同步到当前线程的工作内存,然后再从工作内存同步到主内存,这中间会经历Java内存模型中定义的三种操作use→assign→write ,然后可能会触发缓存一致性协议,使其他线程工作内存中的 race 变量全部失效,其他线程下次获取 race 变量值,都要从主内存中重新获取最新值。

但是,对于未使用volatile 修饰的变量而言,use→assign→write,这三个操作并不是原子性的,这也就意味着其并不是线程安全的。假设有thread-1和thread-2两个线程,thread-1和thread-2工作内存中保留着 race 副本,thread-1对 race 进行了重新赋值,但是其最新值还未同步到主内存,此时thread-2线程读取 race 变量,那么就会直接命中其工作内存获取一个旧数据。

而 volatile 变量将read load use 三个原子操作变成一个原子操作;将assi

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值