首页 > 编程笔记 > Java笔记 阅读:12

JMM是什么,JMM的特征和作用(新手必看)

JMM 是 Java Memory Model(Java 内存模型)的缩写,与 JVM 内存结构不同,它是一个抽象的概念,描述的是一组与多线程相关的规范,需要各个 JVM 的实现来遵守,开发者可以利用这些规范,更方便地开发多线程程序。

在使用 JMM 的情况下,即便同一个程序在不同的虚拟机上运行,得到的程序结果也是一致的。

JMM 定义了程序中的操作如何在多线程环境下交互,以及线程如何通过内存进行通信。当有多个线程操作内存中的共享数据时,JMM 定义了线程与主内存之间的抽象关系以及同步这些操作的方式,确保线程安全性、内存的可见性、原子性和有序性。

JMM规范的主要内容

1) 变量的存储

JMM 描述了程序中的变量如何存储在内存中,以及如何通过线程访问这些变量。

所有变量存放在主内存中,而每个线程有自己的工作内存,工作内存用于存放该线程使用到的主内存变量副本。线程对变量的操作都在工作内存中进行。线程不能直接读写主内存中的变量。

每个线程的工作内存都是独立的,线程只能先在工作内存中操作变量,然后将变量同步到主内存,如下图所示。

2) 操作的原子性

JMM 规定哪些操作是原子性的,即不可中断的。

例如,对于非 long 或 double 类型的变量的读写操作通常是原子性的,但这些操作的复合操作(如递增操作)不是原子性的。

3) 变量的可见性

JMM 规定何时以及如何将更新后的变量值从工作内存同步到主内存,以及从主内存更新到各个线程的工作内存,确保一个线程对共享变量的修改对其他线程可见。

4) 变量修改的有序性

JMM 规定在不影响单线程程序执行结果的前提下,允许编译器和处理器对操作顺序进行重排序,但必须遵守特定的规则(比如使用 volatile 关键字、final 关键字和 synchronized 块/方法)以保证在多线程环境中程序的有序性和正确性。

5) 锁的语义

JMM 定义了锁和同步的语义,确保获取锁的线程能看到由先前持有同一锁(并已释放该锁)的其他线程所作的修改。

JMM的特征和作用

整个 JMM 实际上是围绕着以下 3 个特征建立起来的,这 3 个特征可谓是整个 Java 并发编程的基础。

1) 原子性(Atomicity)

原子性是指一个或一系列操作是不可中断的,即使是在多线程同时执行的情况下,一个操作(或对某个变量的操作)要么完全执行,要么完全不执行,不会停留在中间某个步骤。

JMM 只能保证基本的原子性,如果要保证一个代码块的原子性,可以通过 synchronized 或 java.util.concurrent 包中的原子类(如 AtomicInteger)来保证。

2) 可见性(Visibility)

可见性是指如果一个线程修改了共享变量的值,其他线程能够立刻得知这个修改。

Java 提供了 volatile 关键字来保证变量的可见性,用 volatile 修饰一个共享变量可以保证对这个变量的读写都是直接操作主内存,而不是线程的工作内存。

3) 有序性(Ordering)

有序性是指程序按照代码的先后顺序执行。在 JMM 中,由于编译器优化和处理器优化,可能会出现指令重排序,打乱原来的代码执行顺序。

为了解决这个问题,JMM 提出了 happens-before 原则来保证程序的有序性。通过 synchronized 或 volatile 也可以保证多线程之间操作的有序性。

总之,JMM 规范屏蔽掉了各种硬件和操作系统的内存访问差异与实现细节,这些细节对于 Java 开发者而言是透明的,理解 JMM 提供的规则和保障对编写正确的并发程序至关重要。

通过遵循 JMM 规范,开发者可以编写出既安全又高效的多线程 Java 程序,并且让 Java 程序在不同平台上都能达到一致的内存访问效果,这就是 JMM 的意义。

相关文章