java 多线程 volatile 与 synchronized

volatile 与 synchronized 的比较

1、volatile

(1)可见性

写操作:

对volatile变量的写操作,会紧跟一个LOCK前缀指令,LOCK前缀的指令效果是把工作内存中的变更(可以理解为写缓冲区)都写到主内存中,并且使得其他cpu关于这部分数据的缓存行也都失效(MESI机制)。其他线程(cpu)读取这部分变量时,就会从主内存中重新读取。这样就保证了这部分数据的可见性。而volatile变量自然也被包含在这部分数据中,毕竟刷回主内存本身就是volatile的作用。

读操作:

如果线程A读取了一个volatile变量,则读取该volatile变量时线程A可见的所有变量也将从主内存中重新读取。(读取了一个volatile变量,则当前线程A的读缓存失效(清空),后续使用共享变量时需要重新读取主内存)

(2)禁止指令重排序

 

 

2、synchronized

有三大特性:原子性,有序性,可见性

(1)原子性

多个指令作为一个整体,其他指令不会插到这个整体间,只能在这个整体执行前或者执行后才能执行。

(2)有序性

synchronized保证的有序性是多个线程之间的有序性,即被加锁的内容要按照顺序被多个线程执行

synchronized 并没有禁止指令重排序的功能,也就是说synchronized 代码块中的代码指令还是会指令重排序。

synchronized 是怎么保证有序性的呢?

具体解释请看:https://www.cnblogs.com/hollischuang/p/11386988.html

所以单例模式中使用双重检查之后(第二重检查还加了synchronized),也还是不能保证可见性和有序性,还需要给字段加volatile才能保证。

(3)可见性

在Java内存模型中,synchronized规定,线程在加锁时,

获取锁→先清空工作内存→在主内存中拷贝最新变量的副本到工作内存→执行完代码→将更改后的共享变量的值刷新到主内存中→释放锁

(注意:加锁与解锁需要是同一把锁)

通过以上两点,可以看到synchronized能够实现可见性。但是有个明显的缺点:synchronized代码块只保证在释放锁前才把对共享变量的修改刷新回主内存。。而在同步代码块执行期间对共享变量的修改,还在暂存于工作内存中,并不是立即刷到主内存的,对其他线程不一定可见。(单例模式双重检查加volatile的原因之一)

所以synchronized的可见性并不是真正的可见性。volatile才是。

 

可以参考这几篇文章:

https://blog.csdn.net/singwhatiwanna/article/details/104421561/

https://www.zhihu.com/question/337265532/answer/794398131

https://www.cnblogs.com/hollischuang/p/11386988.html

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值