并发编程

Java 并发编程

Java 内存模型(Java Memory Model, JMM)

Java 内存模型着眼于描述 Java 中的线程是如何与内存进行交互,以及单线程中代码执行的顺序等,并提供了一系列基础的并发语义原则;最早的 Java 内存模型于 1995 年提出,致力于解决不同处理器/操作系统中线程交互/同步的问题,规定和指引 Java 程序在不同的内存架构、CPU 和操作系统间有确定性地行为。在 Java 5 版本之前,JMM 并不完善,彼时多线程往往会在共享内存中读取到很多奇怪的数据;譬如,某个线程无法看到其他线程对共享变量写入的值,或者因为指令重排序的问题,某个线程可能看到其他线程奇怪的操作步骤。

Java 内存模型具备一些先天的“有序性”,即不需要通过任何手段就能够得到保证的有序性,这个通常也称为 happens-before 原则。如果两个操作的执行次序无法从 happens-before 原则推导出来,那么它们就不能保证它们的有序性,虚拟机可以随意地对它们进行重排序。

Java 内存模型对一个线程所做的变动能被其它线程可见提供了保证,它们之间是先行发生关系。

  • 线程内的代码能够按先后顺序执行,这被称为程序次序规则

  • 对于同一个锁,一个解锁操作一定要发生在时间上后发生的另一个锁定操作之前,也叫做管程锁定规则

  • 前一个对 volatile 的写操作在后一个 volatile 的读操作之前,也叫 volatile 变量规则

  • 一个线程内的任何操作必需在这个线程的 start()调用之后,也叫作线程启动规则

  • 一个线程的所有操作都会在线程终止之前,线程终止规则

  • 一个对象的终结操作必需在这个对象构造完成之后,也叫对象终结规则

对于程序次序规则来说,就是一段程序代码的执行在单个线程中看起来是有序的。注意,虽然这条规则中提到“书写在前面的操作先行发生于书写在后面的操作”,这个应该是程序看起来执行的顺序是按照代码顺序执行的,因为虚拟机可能会对程序代码进行指令重排序。虽然进行重排序,但是最终执行的结果是与程序顺序执行的结果一致的,它只会对不存在数据依赖性的指令进行重排序。因此,在单个线程中,程序执行看起来是有序执行的,这一点要注意理解。事实上,这个规则是用来保证程序在单线程中执行结果的正确性,但无法保证程序在多线程中执行的正确性。

链接