预备知识
CPU 缓存模型
CPU Cache 缓存的是内存数据用于解决 CPU 处理速度和内存不匹配的问题,内存缓存的是硬盘数据用于解决硬盘访问速度过慢的问题。
指令重排序
为了提升执行速度/性能,计算机在执行程序代码的时候,会对指令进行重排序。
什么是指令重排序? 简单来说就是系统在执行代码的时候并不一定是按照你写的代码的顺序依次执行。
常见的指令重排序有下面 2 种情况:
- 编译器优化重排:编译器(包括 JVM、JIT 编译器等)在不改变单线程程序语义的前提下,重新安排语句的执行顺序。
- 指令并行重排:现代处理器采用了指令级并行技术(Instruction-Level Parallelism,ILP)来将多条指令重叠执行。如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序。
Java 源代码会经历 编译器优化重排 —> 指令并行重排 —> 内存系统重排 的过程,最终才变成操作系统可执行的指令序列。
指令重排序可以保证串行语义一致,但是没有义务保证多线程间的语义也一致 ,所以在多线程下,指令重排序可能会导致一些问题。
JMM 相关概念
- 什么是 JMM?
JMM(Java Memory Model)是Java内存模型,它**主要定义了对于一个共享变量,当另一个线程对这个共享变量执行写操作后,这个线程对这个共享变量的可见性。**JMM抽象了线程和主内存之间的关系,规定了从Java源代码到CPU可执行指令的转化过程中,与并发相关的原则和规范。它确保了在多线程环境下,对共享变量的操作能够保持一致性和可见性。
- 它解决了什么问题?
JMM解决了多线程编程中的内存一致性问题。在多线程环境中,由于线程可能有自己的本地内存(如CPU缓存),这可能导致不同线程对共享变量的读写操作出现不一致的情况。JMM通过定义一系列规则,确保了在多线程环境下,对共享变量的修改能够被其他线程正确地看到,从而保证了程序的正确性和可移植性。
- 如何解决的?
JMM通过定义了一系列同步操作(如lock、unlock、read、load、use、assign、store、write等)和同步规则,以及happens-before原则,来确保线程间的操作顺序和可见性。这些规则和原则限制了编译器和处理器对指令的重排序,以防止它们破坏多线程程序的正确性。例如,happens-before原则规定了操作之间的顺序关系,确保了在某些操作之后进行的操作能够看到之前操作的结果。
Java 内存区域和 JVM 有何区别?
这是一个比较常见的问题,很多初学者非常容易搞混。 Java 内存区域和内存模型是完全不一样的两个东西:
- JVM 内存结构和 Java 虚拟机的运行时区域相关,定义了 JVM 在运行时如何分区存储程序数据,就比如说堆主要用于存放对象实例。
- Java 内存模型和 Java 的并发编程相关,抽象了线程和主内存之间的关系就比如说线程之间的共享变量必须存储在主内存中,规定了从 Java 源代码到 CPU 可执行指令的这个转化过程要遵守哪些和并发相关的原则和规范,其主要目的是为了简化多线程编程,增强程序可移植性的。