Java volatile自我理解

Java volatile详解

volatile是什么

用volatile修饰的变量,线程在每次使用变量的时候,都会读取变量修改后的最的值。volatile很容易被误用,用来进行原子性操作。

在Java线程并发处理中,有一个关键字volatile的使用目前存在很大的混淆,以为使用这个关键字,在进行多线程并发处理的时候就可以万事大吉。

Java语言是支持多线程的,为了解决线程并发的问题,在语言内部引入了 同步块(synchronized) 和 volatile 关键字机制。

volatile需处理问题

举个例⼦,⽐如说有两个线程,他们的代码⾥都需要读取 data 这个变量的值,那么他们都会从主内存⾥加载 data 变量的值到⾃⼰的⼯作内存,然后才可以使⽤那个值。

如果线程1关联的是工作内存1里面的data值,而线程2关联的是工作内存2里面的data值,那么线程1对工作内存1的值进行改变后,确不会对线程2里面的data值进行变更。而volatile就是解决这个问题使用的。下面来几张图!
在这里插入图片描述如上图,这张图说的是 java 内存模型中,每个线程有⾃⼰的⼯作内存,同时还有⼀个共享的主内存。
举个例⼦,⽐如说有两个线程,他们的代码⾥都需要读取 data 这个变量的值,那么他们都会从主内存⾥加载 data 变量的值到⾃⼰的⼯作内存,然后才可以使⽤那个值。
好了,现在⼤家从图⾥看到,每个线程都把 data 这个变量的副本加载到了⾃⼰的⼯作内存⾥了,所以每个线程都可以读到 data = 0 这个值。
这样,在线程代码运⾏的过程中,对 data 的值都可以直接从⼯作内存⾥加载了,不需要再从主内存⾥加载了。

我们来设想⼀下,假如说线程 1 修改了 data 变量的值为 1,然后将这个修改写⼊⾃⼰的本地⼯作内存。那么此时,线程 1 的⼯作内存⾥的 data 值为 1。

然⽽,主内存⾥的 data 值还是为 0!线程 2 的⼯作内存⾥的 data 值还是 0 啊?!

在这里插入图片描述
这可尴尬了,那接下来,在线程 1 的代码运⾏过程中,他可以直接读到 data 最新的值是 1,但是线程 2 的代码运⾏过程中读到的 data 的值还是 0!
这就导致,线程 1 和线程 2 其实都是在操作⼀个变量 data,但是线程 1 修改了 data 变量的值之后,线程 2 是看不到的,⼀直都是看到⾃⼰本地⼯作内存中的⼀个旧的副本的值!
这就是所谓的 java 并发编程中的可⻅性问题:多个线程并发读写⼀个共享变量的时候,有可能某个线程修改了变量的值,但是其他线程看不到!也就是对其他线程不可见!

volatile的作用以及原理

那如果要解决这个问题怎么办呢?这时就轮到 volatile 闪亮登场了!你只要给 data 这个变量在定义的时候加⼀个 volatile,就直接可以完美的解决这个可⻅性的问题。
⽐如下⾯的这样的代码,在加了 volatile 之后,会有啥作⽤呢?

在这里插入图片描述
第⼀,⼀旦 data 变量定义的时候前⾯加了 volatile 来修饰的话,那么线程 1 只要修改 data 变量的值,就会在修改完⾃⼰本地⼯作内存的 data 变量值之后,强制将这个 data 变量最新的值刷回主内存,必须让主内存⾥的 data 变量值⽴⻢变成最新的值!

整个过程,如下图所示:

在这里插入图片描述
第⼆,如果此时别的线程的⼯作内存中有这个 data 变量的本地缓存,也就是⼀个变量副本的话,那么会强制让其他线程的⼯作内存中的 data 变量缓存直接失效过期,不允许再次读取和使⽤了!

整个过程,如下图所示:

在这里插入图片描述
第三,如果线程 2 在代码运⾏过程中再次需要读取 data 变量的值,此时尝试从本地⼯作内存中读取,就会发现这个 data = 0 已经过期了!
此时,他就必须重新从主内存中加载 data 变量最新的值!那么不就可以读取到 data = 1 这个最新的值了!

整个过程,参⻅下图:

在这里插入图片描述
好了,volatile 完美解决了 java 并发中可⻅性的问题!对⼀个变量加了 volatile 关键字修饰之后,只要⼀个线程修改了这个变量的值,⽴⻢强制刷回主内存。

接着强制过期其他线程的本地⼯作内存中的缓存,最后其他线程读取变量值的时候,强制重新从主内存来加载最新的值!这样就保证,任何⼀个线程修改了变量值,其他线程⽴⻢就可以看⻅了!这就是所谓的 volatile保证了可⻅性的⼯作原理!

总结

volatile 主要作⽤是保证可⻅性以及有序性。有序性涉及到较为复杂的指令重排、内存屏障等概念,本⽂没提及,但是 volatile 是不能保证原⼦性的!

也就是说,volatile 主要解决的是⼀个线程修改变量值之后,其他线程⽴⻢可以读到最新的值,是解决这个问题的,也就是可⻅性!但是如果是多个线程同时修改⼀个变量的值,那还是可能出现多线程并发的安全问题,导致数据值修改错乱,volatile 是不负责解决这个问题的,也就是不负责解决原⼦性问题!

原⼦性问题,得依赖 synchronized、ReentrantLock 等加锁机制来解决。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值