volatile关键字个人理解

Volatile与Synchronized解析
本文深入探讨了Java中volatile关键字如何确保数据的可见性和有序性,对比synchronized关键字,阐述两者在多线程环境下的作用及差异。

一、效果

1、保证代码的可见性

保证被修饰的变量被修改时,直接跳过修改缓存,直接修改其主存值。

主存就相当于计算机中的物理内存,而CPU运算速度很高,所以在CPU中为了同步数据,出现了CPU高速缓存。

举例说明,如下图代码:

int a = 0;
//线程1
a = 1;
//线程2
a += 1;

每个线程有各自的内存空间,当变量a没有被volatile修饰符修饰时,每一个线程都会从主存中复制一遍数据,作为自己的高速缓存,此时如果线程1执行完毕过后,而线程1的高速缓存还没有与主存进行统一。这时线程2自然取到的数字还是0,因为在线程2的高速缓存中,此数据并没有被更新。

此时我们给变量a加上volatile关键字,代码如下:

volatile int a = 0;
//线程1
a += 1;
//线程2
a += 1;

被volatile修饰的关键字,如果值被修改,则跳过高速缓存立刻写入主存,所以当线程1执行后,此时主存中的数据已经被修改,而线程2也会直接从主存中取到当前值,所以会取到数字1。

同时作为多线程非常重要的关键字,volatile与synchronized还是有很大的区别的,因为synchronized是给对象加锁,从而可以保证操作的原子性,而volatile就不能做到这一点。

我们回顾上方代码会发现一个问题:因为a没有被synchronized修饰,所以两个线程可以同时取到变量a。

我们知道a += 1不是原子性操作,是先取到a的值,再对a的值进行自增,再存入a。

如果两个线程同时拿到a的值,即都为0,此时两个线程计算出a的结果都是1,此时同时存入。

虽然保证了代码的可见性,但是此时两个线程都想将主存中的值改为1。而我们知道数据正常应该为2。所以并没有保证原子性。

如果我们将关键字改为synchronized就不会再出现这种情况了。

synchronized int a = 0;
//线程1
a += 1;
//线程2
a += 1;

总结一下:

volatile关键字可以保证数据永远取到的是最新的值,但是无法保证多个线程同时操作一个值时计算结果的正确。可能会出现计算冲突。所以只能保证数据的可见性。

而synchronized关键字的本质是为加锁,永远保证只有一个线程可以操作此变量,这样会导致效率降低,但是更加安全,保证了数据的可见性与原子性。

 

2、保证代码的有序性

保证被修饰的代码被编译后不会被调整顺序。

由于jvm的优化,我们经过编译后的代码通常不会与我们编写的顺序一致。

所以当有些关键操作有明确的代码顺序关系时。可以为变量添加volatile关键字,保证此代码块不会被调整顺序。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值