- 冲刺高薪Offer:Java并发编程进阶及面试指南
- 吴晓勇 梁建全编著
- 1300字
- 2025-03-13 18:03:39
1.2.3 JMM内存是如何交互的?都有哪些操作?
在JMM中,所有的变量都存储在主内存中,每个线程有自己的工作内存。线程的工作内存中保存了该线程使用到的变量,它们是从主内存复制的副本。线程对变量的所有操作(比如读取、赋值等)都必须在工作内存中进行,而不能直接在主内存中进行,并且每个线程不能访问其他线程的工作内存。为了实现JMM这个特性,JMM定义了8种内存操作,具体如下。
● lock:锁定操作,作用于主内存的变量,它标记一个变量开始处于独占状态。
● unlock:解锁操作,作用于主内存的变量,它标记一个变量结束独占状态。
● read:读取操作,作用于主内存的变量,它将一个变量的值从主内存传输到线程的工作内存中,以便随后的载入操作使用。
● load:载入操作,作用于工作内存的变量,它在读取操作之后执行,将读取操作得到的值放入工作内存的主内存变量副本中。
● use:使用操作,作用于工作内存的变量,它将工作内存中的一个变量的值传递给线程使用。
● assign:赋值操作,作用于工作内存的变量,线程通过它将一个值赋给工作内存中的变量。
● store:存储操作,作用于工作内存的变量,它将工作内存中的一个变量的值传递到主内存中,以便随后的写入操作使用。
● write:写入操作,作用于主内存的变量,它在存储操作之后执行,将存储操作得到的值放入主内存的变量中。
上述这些内存操作必须按照特定的顺序执行,这个顺序由happens-before原则来定义,具体交互过程如图1-3所示。

图1-3
JMM还规定了执行上述8种内存操作时必须满足的规则,具体如下。
● 如果要把一个变量从主内存中复制到工作内存,就需要按顺序执行读取和载入操作;如果要把一个变量从工作内存同步回主内存,就需要按顺序执行存储和写入操作。但JMM只要求上述操作必须按顺序执行,而没有要求必须连续执行。
● 不允许读取和载入、存储和写入操作之一单独出现。
● 不允许一个线程丢弃它最近的赋值操作,即变量在工作内存中改变了之后必须同步到主内存中。
● 不允许一个线程无原因(没有发生过任何赋值操作)地把数据从工作内存同步到主内存中。
● 一个新的变量只能在主内存中诞生,不允许在工作内存中直接使用一个未被初始化(载入或赋值)的变量,即对一个变量实施使用和存储操作之前,必须先执行赋值和载入操作。
● 对于一个变量,在同一时刻只允许一个线程对其进行锁定操作,但锁定操作可以被同一个线程重复执行多次,多次执行锁定操作后,只有执行相同次数的解锁操作,变量才会被解锁。锁定和解锁操作必须成对出现。
● 如果对一个变量执行锁定操作,将会清空工作内存中此变量的值,在执行引擎使用这个变量前需要重新执行载入或赋值操作初始化变量的值。
● 如果一个变量事先没有被锁定操作锁定,则不允许对它执行解锁操作;也不允许对一个被其他线程锁定的变量执行解锁操作。
● 对一个变量执行解锁操作之前,必须把此变量同步到主内存中。
JMM通过上述操作,结合happens-before原则,定义了线程通过主内存交互的方式,同步变量到工作内存的方式,以及工作内存与主内存之间的关系,等等。这些原则确保了在多线程环境中,共享变量的更新能够被其他线程看到,从而使得线程间的通信变得可靠和高效。这些操作基本上构成了线程间通过共享内存进行通信的基础,保证了Java程序在多线程环境中能有正确的并发行为。