资讯专栏INFORMATION COLUMN

【Java猫说】Java多线程之内存可见性(下篇)

elliott_hu / 1394人阅读

摘要:阅读本文约分钟上一次我们说到互斥代码的实现过程,如果有忘记或不清楚的可以去上篇看看。猫说多线程之内存可见性上篇今天我们了解下重排序。

阅读本文约“3分钟”

上一次我们说到synchronized互斥代码的实现过程,如果有忘记或不清楚的可以去上篇看看。
【Java猫说】Java多线程之内存可见性(上篇)

今天我们了解下重排序。

其使代码书写的顺序与实现执行的顺序不同,指令重排序是编译器或处理器为了提高程序性能而做的优化,可以分为
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
欢迎留言讨论与点赞
上一篇推荐:【Java猫说】Java多线程之内存可见性(上篇)
下一篇推荐:【Java猫说】Java对象的行为

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/71646.html

相关文章

  • Java猫说Java线程内存可见(上篇)

    摘要:猫说多线程之内存可见性下篇欢迎你留言讨论属于你的见解,毕竟每个人的味蕾都不一样,这杯咖啡有吸引到你吗好像又是一个槽糕的比喻本文已转载个人技术公众号欢迎留言讨论与点赞上一篇推荐猫说主数据类型和引用下一篇推荐猫说多线程之内存可见性下篇 阅读本文约3分钟 本文大致讲述两种线程实现的可见性,或许你已经提前想到了,那说明你的基础很好,我们要聊聊synchronized实现可见性与volatil...

    khlbat 评论0 收藏0
  • Java猫说Java对象的行为

    摘要:阅读本文约分钟对象的行为,这里的对象即上一章中的类吧浅意状态影响行为,行为影响状态这是一个令人深思的话题了。是通过值传递的,也就是说通过拷贝传递。声明一个类型的变量并赋值为,代表的字节组合会放进称为的变量中。 阅读本文约2分钟 对象的行为,这里的对象即上一章中的类吧(浅意) 状态影响行为,行为影响状态! 这是一个令人深思的话题了。 同一类型的每个对象能够有不同的方法行为吗? 仔细想一...

    includecmath 评论0 收藏0
  • Java猫说】主数据类型和引用

    摘要:阅读本文约分钟变量有两种主数据类型和引用。主数据类型用来保存基本类型的值,包括整数,布尔和浮点数等,而对象引用保存的是对象的引用。而在中,主数据类型也有不用的大小与名称。 阅读本文约2.3分钟 变量有两种:primitive主数据类型和引用。 Java注重类型。它不会让你做出把长颈鹿类型变量装进兔子类型变量中这种诡异又危险的举动——如果有人对长颈鹿调用跳跃这个方法会发生什么悲剧?并且...

    dongfangyiyu 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<