- 冲刺高薪Offer:Java并发编程进阶及面试指南
- 吴晓勇 梁建全编著
- 1305字
- 2025-03-13 18:03:39
1.2.1 什么是JMM?它有哪些特征和作用?
JMM是Java Memory Model(Java内存模型)的缩写,与JVM内存结构不同,它是一个抽象的概念,描述的是一组与多线程相关的规范,需要各个JVM的实现来遵守,开发者可以利用这些规范,更方便地开发多线程程序。在使用JMM的情况下,即便同一个程序在不同的虚拟机上运行,得到的程序结果也是一致的。
JMM定义了程序中的操作如何在多线程环境下交互,以及线程如何通过内存进行通信。当有多个线程操作内存中的共享数据时,JMM定义了线程与主内存之间的抽象关系以及同步这些操作的方式,确保线程安全性、内存的可见性、原子性和有序性,以下是JMM规范定义的主要内容。
(1)变量的存储。
JMM描述了程序中的变量如何存储在内存中以及如何通过线程访问这些变量。所有变量存放在主内存中,而每个线程有自己的工作内存,工作内存用于存放该线程使用到的主内存变量副本。线程对变量的操作都在工作内存中进行。线程不能直接读写主内存中的变量。每个线程的工作内存都是独立的,线程只能先在工作内存中操作变量,然后将变量同步到主内存,如图1-2所示。

图1-2
(2)操作的原子性。
JMM规定哪些操作是原子性的,即不可中断的。例如,对于非long或double类型的变量的读写操作通常是原子性的,但这些操作的复合操作(如递增操作)不是原子性的。
(3)变量的可见性。
JMM规定何时以及如何将更新后的变量值从工作内存同步到主内存,以及从主内存更新到各个线程的工作内存,确保一个线程对共享变量的修改对其他线程可见。
(4)变量修改的有序性。
JMM规定在不影响单线程程序执行结果的前提下,允许编译器和处理器对操作顺序进行重排序,但必须遵守特定的规则(比如使用volatile关键字、final关键字和synchronized块/方法)以保证在多线程环境中程序的有序性和正确性。
(5)锁的语义。
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的意义。