Java中【内存屏障】的来龙去脉

文章目录

  • 一、为什么需要内存屏障
  • 二、内存屏障定义
  • 三、Java中的内存屏障:volatile关键字和同步代码块(synchronized blocks)

一、为什么需要内存屏障

众所周知,CPU、内存、I/O 设备的速度是有极大差异的,为了合理利用 CPU 的高性能,平衡这三者的速度差异,计算机体系结构、操作系统、编译程序都做出了贡献,主要体现为:

  • CPU 增加了缓存,以均衡与内存的速度差异;// 导致 可见性问题
  • 操作系统增加了进程、线程,以分时复用 CPU,进而均衡 CPU 与 I/O 设备的速度差异;// 导致 原子性问题
  • 编译程序优化指令执行次序,使得缓存能够得到更加合理地利用。// 导致 有序性问题# 线程不安全示例

其中:编译程序优化指令执行次序指的是,JVM在真正执行代码的时候并不一定按照我们写好的代码顺序去运行指令, 这里可能会发生指令重排序(Instruction Reorder)。

在执行程序时为了提高性能,编译器和处理器常常会对指令做重排序。重排序分三种类型:

  • 编译器优化的重排序。编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序。
  • 指令级并行的重排序。现代处理器采用了指令级并行技术(Instruction-Level Parallelism, ILP)来
  • 将多条指令重叠执行。如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序。内存系统的重排序。由于处理器使用缓存和读 / 写缓冲区,这使得加载和存储操作看上去可能是在乱序执行。

从 java 源代码到最终实际执行的指令序列,会分别经历下面三种重排序:
在这里插入图片描述
上述的 1 属于编译器重排序,2 和 3 属于处理器重排序。这些重排序都可能会导致多线程程序出现内存可见性问题。对于编译器,JMM 的编译器重排序规则会禁止特定类型的编译器重排序(不是所有的编译器重排序都要禁止)。对于处理器重排序,JMM 的处理器重排序规则会要求 java 编译器在生成指令序列时,插入特定类型的内存屏障(memory barriers,intel 称之为 memory fence)指令,通过内存屏障指令来禁止特定类型的处理器重排序(不是所有的处理器重排序都要禁止)。

二、内存屏障定义

内存屏障(Memory Barrier),也称为内存栅栏或内存栅障,是一种特殊的硬件指令,用于在多核处理器系统中同步对内存的访问。内存屏障的主要作用是确保内存操作的顺序性,防止指令重排序和缓存一致性问题,从而在多线程环境中保持数据的正确性和可见性。

在现代计算机系统中,CPU为了提高性能,会采用指令重排序和缓存机制。指令重排序是编译器和处理器为了优化执行效率而进行的一种行为,它们可能会改变指令的执行顺序。缓存机制则是为了减少
CPU访问主内存的次数,提高数据访问速度而采用的局部存储技术。

然而,这些优化在单线程环境中不会引起问题,因为重排序后的执行结果与原始代码的语义相同,且缓存机制确保了数据的局部性。但在多线程环境中,这些问题就会变得复杂。一个线程对数据的修改可能由于缓存未及时刷新到主内存,导致其他线程读取到旧的数据。此外,指令重排序可能会导致一个线程看到一个未完全构造的对象,因为对象的初始化代码被重排序到了对象引用赋值之后。
内存屏障就是为了解决这些问题而设计的。它提供了一种机制,可以强制执行某些内存操作,确保这些操作的顺序性和可见性。内存屏障分为两种类型:

  • 写内存屏障(Store Memory Barrier):确保在屏障指令之前的所有写操作都写入主内存,使得其他线程能够看到这些写操作的结果。这通常用于确保一个线程对共享数据的修改对其他线程立即可见。
  • 读内存屏障(Load Memory Barrier):确保在屏障指令之后的读操作都从主内存中读取数据,而不是从缓存中读取。这通常用于确保一个线程读取到的数据是最新的,不会被旧的缓存数据所影响。

内存屏障的使用通常需要编程者或编译器具备相关知识,以便在关键代码段插入屏障指令,确保多线程之间的数据同步。在硬件层面,内存屏障通常由处理器提供,并且在执行时可能会伴随着缓存刷新和/或指令重排序的抑制。

三、Java中的内存屏障:volatile关键字和同步代码块(synchronized blocks)

在Java中,内存屏障的实现是通过Java虚拟机(JVM)来完成的。JVM在执行Java程序时,会根据程序的语义和硬件平台的特性来插入内存屏障指令。这些指令确保了内存操作的顺序性和数据的可见性,特别是在多线程环境中。

Java中的内存屏障主要与volatile关键字和同步代码块(synchronized blocks)有关。

你可能感兴趣的:(面试,学习Java必看,java,开发语言)