现代 CPU 支持多级指令流水线,几乎所有的冯•诺伊曼型计算机的 CPU,其工作都可以分为 5 个阶段:取指令、指令译码、执行指令、访存取数和结果写回,可以称之为五级指令流水线 。CPU 可以在一个时钟周期内,同时运行五条指令的不同阶段(每个线程不同的阶段),本质上流水线技术并不能缩短单条指令的执行时间,但变相地提高了指令地吞吐率 。
文章插图
处理器在进行重排序时,必须要考虑指令之间的数据依赖性
- 单线程环境也存在指令重排,由于存在依赖性,最终执行结果和代码顺序的结果一致
- 多线程环境中线程交替执行,由于编译器优化重排,会获取其他线程处在不同阶段的指令同时执行
使用volatile关键字 。
文章插图
【深刻理解JAVA并发中的有序性问题和解决之道】volatile 的底层实现原理是内存屏障,Memory Barrier(Memory Fence)
- 对 volatile 变量的写指令后会加入写屏障
- 对 volatile 变量的读指令前会加入读屏障
内存屏障分为写屏障和读屏障,有什么有呢?
- 保证可见性
- 写屏障保证在该屏障之前的,对共享变量的改动,都同步到主存当中
- 读屏障保证在该屏障之后,对共享变量的读取,加载的是主存中最新数据
- 保证有序性
- 写屏障会确保指令重排序时,不会将写屏障之前的代码排在写屏障之后
- 读屏障会确保指令重排序时,不会将读屏障之后的代码排在读屏障之前
文章插图
回到前面的问题,如果对ready加了volatile以后,那么num=2就无法到后面去了,同样读取也是,如上图所示 。
final底层也是通过内存屏障实现的,它与volatile一样 。总结JAVA并发中的有序性问题其实比较难理解,本文通过一个例子验证了并发情况下会出现有序性的问题,从而引发意想不到的结果 。这个主要的原因是为了提高性能,指令会发生重排序导致的 。为了解决这样的问题,我们可以使用volatile这个关键字修饰变量,它能够保证有序性和可见性,但是无法保证原子性 。如果以后遇到一些成员变量或者静态变量就要特别注意了,需要分析并发情况下会有哪些问题 。
对final变量的写指令加入写屏障 。也就是类初始化的赋值的时候会加上写屏障 。
对final变量的读指令加入读屏障 。加载内存中final变量的最新值 。
推荐阅读
- 人生感悟的句子,睿智深刻,让人忍不住落泪!
- 张艺兴被问“小奶狗和小狼狗”意思,听完他的理解网友直呼:直男
- 高考:西周以血缘关系为宗法制,周朝分封制基础,对后世深刻影响
- 什么叫割礼女孩 什么叫割礼
- 高山流水成语故事寓意深刻 高山流水成语
- 如何理解平移函数的图像? 平移图形
- 如何理解经营策略 经营策略
- 如何理解古诗词中的意象? 什么是意象
- 怎样理解“君子之交淡如水”这句成语的? 君子之交淡如水是什么意思
- 伊能静|伊能静回应婚变:去美国是照顾儿子,感谢秦昊的理解!