Java内存模型(Java Memory Model,JMM)是Java虚拟机规范定义的一种抽象概念,用于屏蔽不同硬件和操作系统的内存访问差异,保证Java程序在各种平台下都能达到一致的内存访问效果。下面详细介绍它定义的规则和特性:

规则

  1. 原子性规则:指一个操作是不可中断的。在Java中,对基本数据类型的变量的读取和赋值操作是原子性操作。例如x = 10是原子性的,但x++并非原子性,因为它包含读取、加1和写入三个操作。
  2. 可见性规则:当一个变量被声明为volatile时,它会保证对该变量的写操作会立即刷新到主内存,而读操作会从主内存中读取最新的值。此外,synchronizedLock也能保证可见性,因为在释放锁之前会将变量刷新到主内存,在获取锁时会从主内存读取最新值。
  3. 有序性规则:Java程序中,在本线程内观察,所有操作都是有序的;而在另一个线程观察,所有操作都是无序的。这是因为存在指令重排序的情况。不过,volatilesynchronized可以保证有序性。volatile关键字能禁止指令重排序,synchronized则保证同一时刻只有一个线程执行同步代码块,从而保证有序性。

特性

  1. 主内存与工作内存:Java内存模型将内存分为主内存和工作内存。主内存是所有线程共享的,存储了所有的变量;而每个线程都有自己的工作内存,线程的工作内存中保存了被该线程使用到的变量的主内存副本拷贝。线程对变量的所有操作(读取、赋值等)都必须在工作内存中进行,而不能直接读写主内存中的变量。不同线程之间也无法直接访问对方工作内存中的变量,线程间变量值的传递均需要通过主内存来完成。
  2. 指令重排序:为了提高性能,编译器和处理器常常会对指令做重排序。重排序分三种类型:编译器优化的重排序、指令级并行的重排序和内存系统的重排序。从Java源代码到最终实际执行的指令序列,会分别经历这三种重排序。不过,JMM通过插入特定的内存屏障来禁止特定类型的编译器重排序和处理器重排序,以此保证有序性。
  3. 先行发生原则(Happens-Before):这是JMM中定义的两项操作之间的偏序关系,如果说操作A先行发生于操作B,其实就是在说在发生操作B之前,操作A产生的影响能被操作B观察到,“影响”包含了修改了内存中共享变量的值、发送了消息、调用了方法等。常见的先行发生规则有:程序次序规则、管程锁定规则、volatile变量规则、线程启动规则、线程终止规则、线程中断规则、对象终结规则和传递性规则。

通过这些规则和特性,Java内存模型确保了多线程环境下程序的正确性和高效性。