博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【Java猫说】Java多线程之内存可见性(下篇)
阅读量:6621 次
发布时间:2019-06-25

本文共 1281 字,大约阅读时间需要 4 分钟。

阅读本文约“3分钟”


上一次我们说到synchronized互斥代码的实现过程,如果有忘记或不清楚的可以去上篇看看。

今天我们了解下重排序。

其使代码书写的顺序与实现执行的顺序不同,指令重排序是编译器或处理器为了提高程序性能而做的优化,可以分为

1、编译器优化的重排序(编译器优化)
2、指令级并行重排序(处理器优化)
3、内存系统的重排序(处理器优化)

而as-if-serial语义原则是指:无论如何重排序,程序执行的结果应该与代码顺序执行的结果一致(Java编译器、运行时和处理器都会保证Java在单线程下遵循as-if-serial语义)

int num1 = 1;int num2 = 2;int sum = num1 + num2;

对于执行的单线程而言,第1、2行的顺序可以重排,但第3行不能

由此,重排序并不会给单线程带来内存可见性问题

但是在多线程中程序交错执行时,重排序可能会造成内存可见性问题

这里罗列了几个原因,导致共享变量在线程间不可见的原因:

1、线程的交叉执行(synchronized原子性)
2、重排序结合线程交叉执行(synchronized原子性)
3、共享变量更新后的值没有在工作内存与主内存间及时更新(synchronized可见性)

而对于另一个对象volatile而言其实现了可见性,但是不能保证原子性(不能保证volatile变量符合操作是的原子性)

深入来说,是通过加入内存屏障和禁止重排序优化来实现的。

1、对volatile变量执行写操作时,会在写操作后加一条store屏障指令
2、对volatile变量执行读操作时,会在读操作前加入一条load屏障指令

由此我们可以分为读写volatile变量的两种操作。

线程写volatile变量的过程:

1、改变线程工作内存中volatile变量副本的值
2、将改变后的副本的值从工作内存刷新到主内存

线程读volatile变量的过程:

1、从主内存中读取volatile变量的最新值到线程的工作内存中
2、从工作内存中读取volatile变量的副本

注意:volatile是不能保证原子性的

想要在多线程中安全的使用volatile变量,必须同时满足一下几个条件:

1、对变量的写入操作不依赖其当前值

- 不满足:number++、count = count * 5- 满足:boolean变量、记录数据变化的变量等

2、该变量没有包含在具有其他变量的不变式中

- 不满足:不变式 low < up

最后我们来比较下这两个对象吧

- volatile不需要加锁,比synchronized更轻量级,不会阻塞线程- 从内存可见性角度讲,volatile读相当于加锁,volatile写相当于解锁- synchronized即能保证可见性,又能保证原子性,而volatile只能保证可见性,无法保证原子性- volatile没有synchronized使用的广泛

本文已转载个人技术公众号:UncleCatMySelf

欢迎留言讨论与点赞
上一篇推荐:
下一篇推荐:

你可能感兴趣的文章
小游戏-猜数字
查看>>
深度学习到顶,AI寒冬将至!
查看>>
【投资】欧盟区块链创业公司投资超500万欧元
查看>>
优傲机器人:人机协作机器人助推电子制造业智慧升级
查看>>
PHP浮点数的精确计算BCMath
查看>>
[起重机监测系统] 1、基于无线传输的桥式起重机的安全监测方案
查看>>
2014年发展计划
查看>>
QQ协议
查看>>
[Android]一个干净的架构(翻译)
查看>>
Oracle RAC安装过程中碰到的“坑”和关键点(一)
查看>>
Jmeter关联
查看>>
java的nio之:java的nio系列教程之Scatter/Gather
查看>>
linux命令之ldconfig
查看>>
Shell之sed命令
查看>>
如何让你的传输更安全——NIO模式和BIO模式实现SSL协议通信
查看>>
【云计算的1024种玩法】使用 NAS 文件储存低价获得好磁盘性能
查看>>
Android Framework Boot Up Overview(Android系统框架启动流程概述)
查看>>
聊聊 iOS 开发
查看>>
人人都应该了解的信息简史
查看>>
linux c文件操作接口
查看>>