Synchronized和Volatiole关键字的作用及区别

一.synchronized关键字的作用

  1. 多线程共同操作共享数据时。关键字synchronized可以保证在同一时刻,只有一个线程可以执行某个方法或某个代码块;

  2. synchronized可以保证一个线程的变化可见(可见性),即可以代替 volatile。

  3. Synchronized是隐式的获取和释放锁,而且隐式的支持重进入,即获取了锁的线程能够再次获取锁不会自己阻塞自己。

二.volatile关键字作用

  1. 保证变量可见性

  2. 禁止指令重排序
    目的:
    1.避免了多线程环境下程序出现乱序执行的现象 ;
    2.防止编译器和处理器对某些不存在数据依赖的数据进行重排序导致结果出错;

保证此变量对所有的线程的可见性,这里的“可见性”,如本文开头所述,当一个线程修改了这个变量的值,volatile保证了新值能立即同步到主内存,以及每次使用前立即从主内存刷新。但普通变量做不到这点,普通变量的值在线程间传递均需要通过主内存(详见:Java内存模型)来完成.

禁止指令重排序优化。有volatile修饰的变量,赋值后多执行了一个“load addl $0x0, (%esp)”操作,这个操作相当于一个内存屏障(指令重排序时不能把后面的指令重排序到内存屏障之前的位置),只有一个CPU访问内存时,并不需要内存屏障;(什么是指令重排序:是指CPU采用了允许将多条指令不按程序规定的顺序分开发送给各相应电路单元处理)。

三.两者的区别

  1. 关键字volatile是线程同步的轻量级实现,只能修饰变量;synchronized可以修饰方法和代码块;

  2. 多线程访问volatile不会发生阻塞;但synchronzied会阻塞

  3. volatile保证数据的可见性、不保证数据的原子性
    synchronized既保证原子性、又保证可见性,因为会在私有内存与公共内存之间做数据同步

四. 对volatile可见性和不能保证原子性的原因的拓展

一.可见性

可见性与Java的内存模型有关,模型采用缓存与主存的方式对变量进行操作,也就是说,每个线程都有自己的缓存空间,对变量的操作都是在缓存中进行的,之后再将修改后的值返回到主存中,这就带来了问题,有可能一个线程在将共享变量修改后,还没有来的及将缓存中的变量返回给主存中,另外一个线程就对共享变量进行修改,那么这个线程拿到的值是主存中未被修改的值,这就是可见性的问题。

volatile很好的保证了变量的可见性,变量经过volatile修饰后,对此变量进行写操作时,汇编指令中会有一个LOCK前缀指令,这个不需要过多了解,但是加了这个指令后,会引发两件事情:

  1. 将当前处理器缓存行的数据写回到系统内存
  2. 这个写回内存的操作会使得在其他处理器缓存了该内存地址无效

什么意思呢?意思就是说当一个共享变量被volatile修饰时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去内存中读取新值,这就保证了可见性。

二.不具有原子性

问题来了,既然它可以保证修改的值立即能更新到主存,其他线程也会捕捉到被修改后的值,那么为什么不能保证原子性呢?

首先需要了解的是,Java中只有对基本类型变量的赋值和读取是原子操作,如i = 1的赋值操作,但是像j = i或者i++这样的操作都不是原子操作,因为他们都进行了多次原子操作,比如先读取i的值,再将i的值赋值给j,两个原子操作加起来就不是原子操作了。(就是对于非原子的操作不具备原子性的功能)

所以,如果一个变量被volatile修饰了,那么肯定可以保证每次读取这个变量值的时候得到的值是最新的,但是一旦需要对变量进行自增这样的非原子操作,就不会保证这个变量的原子性了。

例如有个volatile修饰的变量 i=1,有两个线程A和B同时操作 i++,如果是原子性操作则预期结果应该 i=3,但实际上不是3
.
主要原因在于 i++ 这个操作本身不是原子性的(可以分为读取 i,执行 i+1 操作,把 i+1 赋值给 i 这三个操作),如果两个线程A和B,他们都读取了主存中的 i 值,A进行了 i+1 的操作,之后被阻塞; B又进行了 i+1 的操作,之后将新值赋值给 i,i 值被刷新回主存,此时由于A已经执行完了 i+1 操作,所以即使主存中的i值改变了,缓存一致性原则将A中的 i 变为新值,但是这个 i 值的改变也不会影响它将之前执行完的 i+1 得到的值赋给 i这一步(即A被阻塞之前i+1的结果已经算成2了,即使现在i更新为2了也不会重新去计算i+1=3),同样导致了最后的结果出错

本文涉及的相关博客如下:

  1. Volatile禁止指令重排序:https://www.cnblogs.com/bbgs-xc/p/12731769.html
  2. https://blog.csdn.net/xdzhouxin/article/details/81236356
  3. https://blog.csdn.net/weixin_42593937/article/details/113048919
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值