Java内存模型
Java内存模型试图屏蔽各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到一致的内存访问效果。
处理器上的寄存器读写速度比内存快几个数量级,为了解决这种速度矛盾,在它们之间加入了高速缓存。同时产生了缓存一致性问题,如果多个缓存共享同一块主内存区域,多个缓存的数据可能不一致,需要协议来解决这个问题。
所有的变量存储在主内存中,每个线程有自己的工作内存,工作内存存储在高速缓存或寄存器中,保存了该线程使用的变量的主内存副本拷贝。线程只能直接操作工作内存中的变量,不同线程之间的变量值传递需要通过主内存来完成。
内存间交互
Java内存模型定义了8个操作来完成主内存和工作内存的交互操作。
- read:把一个变量的值从主内存传输到工作内存中
- load:在 read 之后执行,把 read 得到的值放入工作内存的变量副本中
- use:把工作内存中一个变量的值传递给执行引擎
- assign:把一个从执行引擎接收到的值赋给工作内存的变量
- store:把工作内存的一个变量的值传送到主内存中
- write:在 store 之后执行,把 store 得到的值放入主内存的变量中
- lock:作用于主内存的变量
- unlock
内存模型的三大特性
1. 原子性
原子性就是指一个操作中要么全部执行成功,否则失败。Java内存模型保证了上述的八个操作具有原子性。但是Java内存模型允许虚拟机将没有被volatile修饰的64位数据(long,double)的读写操作划分为两次32位操作进行,因此load,store,read和write操作不具备原子性。但是JMM只保证了上述操作的原子性,像是i++这样的操作,其实是分为获取i,i自增以及赋值给i三步的,如果要实现这样的原子操作就需要使用原子类实现,或者也可以使用它synchronized互斥锁来保证操作的原子性。
2. 可见性
可见性指当一个线程修改了共享变量的值,其它线程能够立即得知这个修改。Java内存模型是通过在变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量值来实现可见性的。
可见性的三种是实现方式:- volatile
- synchronized,对一个变量执行unlock操作之前,必须把变量值同步回主内存。
- final,被 final关键字修饰的字段在构造器中一旦初始化完成,并且没有发生 this 逃逸(其它线程通过 this 引用访问到初始化了一半的对象),那么其它线程就能看见 final 字段的值。
使用 volatile 关键词修饰的变量每次读取都会得到最新的数据,不管哪个线程对这个变量的修改都会立即刷新到主内存。但是 volatile 关键字不能保证操作的原子性。
synchronized和加锁也能能保证可见性,实现原理就是在释放锁之前其余线程是访问不到这个共享变量的。但是和 volatile 相比开销较大。
3. 顺序性
假设有三个语句a,b,c。在同一个线程内,操作是有序的,以a->b->c的顺序执行。但是,JMM在保证最终结果和代码顺序执行结果一致的情况下,为了提高整体效率会进行指令重排。在单线程中重排不会问题,在多小县城中,可能会有数据不一致的问题。
Java中可以使用volatile关键字来保证顺序性,还可以用synchronized和lock来保证。
volatile 关键字通过添加内存屏障的方式来禁止指令重排,即重排序时不能把后面的指令放到内存屏障之前。
通过 synchronized 和 lock 来保证有序性,它保证每个时刻只有一个线程执行同步代码,相当于是让线程顺序执行同步代码。
JVM通过happen-before来保证顺序性
除了使用volatile和synchronized保证顺序性,JVM还规定了先行发生原则,让一个操作无需控制就能先于另一个操作完成。
- 单一线程原则:在一个线程内,程序前面的操作先于后面的操作。
- 管程锁定规则:一个unlock操作先于后面对同一个锁的lock操作发生。
- volatile变量规则:对一个 volatile 变量的写操作先行发生于后面对这个变量的读操作,也就是说读取的值肯定是最新的。
- 线程启动规则:Thread对象的start()方法调用先行发生于此线程的每一个动作。
- 线程加入规则:Thread 对象的结束先行发生于 join() 方法返回。
- 线程中断规则:对线程 interrupt() 方法的调用先行发生于被中断线程的代码检测到中断事件的发生,可以通过 interrupted() 方法检测到是否有中断发生。
- 对象终结规则:一个对象的初始化完成(构造函数执行结束)先行发生于它的 finalize() 方法的开始。
- 传递性:如果操作 A 先行发生于操作 B,操作 B 先行发生于操作 C,那么操作 A 先行发生于操作 C。
参考资料