The Java Memory Model, synchronization and volatile

11 April 2018

一篇关于 Java 内存模型的笔记.

Memory Model

在了解 Java Memory Model 之前先了解一下什么是 Memory Model.

多处理器的系统中通常会有一层或多层内存缓存, 可以提高获取数据的速度, 减少共享内存总线的数据交换. 但是如果正好有两个处理器同时在检查同一个内存位置的话, 它们怎样才能得到相同的值值呢?

在处理器的角度, 内存模型定义了一些条件和限制, 使得其他处理器写到内存里的数据可以被当前线程获取, 当前线程写的数据可以被其他处理器获取.

Java Memory Model

Java Memory Model 描述的是在多线程的情况下什么样的行为是合法的, 以及多线程如何通过内存交互. 它用来描述程序里的变量与底层的计算机系统的关系, 怎样把变量保存到计算机系统的内存或寄存器里以及怎样把它们从内存或寄存器里取出来.

JMM 定义了 volatile, synchronized 等的行为, 并且保证 synchronized 的 Java 程序能在所有架构的处理器上正确运行.

Shared Variables

可以在线程间共享的内存叫做 shared memory 或者 heap memory.

所有的 instance fields, static fields, 以及 array elements 都保存在堆内存.

local variables, formal method parameters 以及 exception handler parameters 都不会在线程间共享, 也不会影响到内存模型.

reorder

编译器可以因为优化重排序某些指令; 处理器也可能在某些情况下不按顺序执行指令. 所以数据可能不是按程序里写的顺序在寄存器, 处理器缓存和主存中移动.

happen before

JMM 在内存操作(如 read field, write field, lock, unlock)和线程操作(如 start, join)设置了部分顺序, 也就是说某些操作 happen before 其他操作. 如果一个操作 happens before 另一个操作, 那么第一个操作的顺序一定保证是在第二个之前, 并且对第二个可见.

happen before 顺序的规则:

Synchronization

Java synchronization 是通过 monitors(locks) 实现的.

Java 的每一个对象都与一个 monitor 相关联, thread 可以对这个 monitor 执行 lock 或者 unlock . 一次只能有一个线程持有这个 monitor 的 lock, 其他尝试获取锁的线程只能阻塞直到它们能获取到这个锁.

no-op synchronized

注意下面这种方式可能会被编译器完全移除.

1
synchronized (new Object()) {}

因为被加锁的是 new Object(), 也就是说在操作之前这个 monitor 不会被加锁, 并且当这个锁释放之后, 不会再有其他线程请求这把锁. 所以编译器可以把这一部分完全移除.

volatile

volatile 的变量有两个特性:

The compiler and runtime are prohibited from allocating them in registers. They must also ensure that after they are written, they are flushed out of the cache to main memory, so they can immediately become visible to other threads. Similarly, before a volatile field is read, the cache must be invalidated so that the value in main memory, not the local processor cache, is the one seen.

编译器和运行时环境被禁止在寄存器中分配 volatile 变量. 同时一旦 volatile 被写入就会立刻被刷入主存. 同样在读取 volatile 变量之前, 处理器的缓存会被置为失效从而保证从主存里获取值.

volatile 变量只能保证可见性, 在不符合以下两台规则的运算场景中, 仍然需要通过加锁(使用 synchronizedjava.util.concurrent 中的原子类) 来保证原子性:

Reference

标签:
  • Java
comments powered by Disqus