Java内存模型—更完整
Java 内存模型试图屏蔽各种硬件和操作系统的内存访问差异,以实现让 Java 程序在各种平台下都能达到一致的内存访问效果。
1、主内存与工作内存
处理器上的寄存器的读写的速度比内存快几个数量级,为了解决这种速度矛盾,在它们之间加入了高速缓存。
加入高速缓存带来了一个新的问题:缓存一致性。如果多个缓存共享同一块主内存区域,那么多个缓存的数据可能会不一致,需要一些协议来解决这个问题。
所有的变量都存储在主内存中,每个线程还有自己的工作内存,工作内存存储在高速缓存或者寄存器中,保存了该线
程使用的变量的主内存副本拷贝。
线程只能直接操作工作内存中的变量,不同线程之间的变量值传递需要通过主内存来完成。
二、内存间交互操作
Java 内存模型定义了 8 个操作来完成主内存和工作内存的交互操作。
- read:把一个变量的值从主内存传输到工作内存中;
- load:在 read 之后执行,把 read 得到的值放入工作内存的变量副本中;
- use:把工作内存中一个变量的值传递给执行引擎;
- assign:把一个从执行引擎接收到的值赋给工作内存的变量;
- store:把工作内存的一个变量的值传送到主内存中;
- write:在 store 之后执行,把 store 得到的值放入主内存的变量中;
- lock:作用于主内存的变量;
- unlock
三、内存模型三大特性
- 原子性:AtomicXxxx类,synchronized;
- 可见性:volatile,synchronized,final;
- 有序性:volatile,synchronized;
名词解释:
- 可见性:指当一个线程修改了共享变量的值,其它线程能够立即得知这个修改。
- 有序性:指在本线程内观察,所有操作都是有序的。在一个线程观察另一个线程,所有操作都是无序的,无序是因为发生了指令重排序。在 Java 内存模型中,允许编译器和处理器对指令进行重排序,重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性。
- volatile并不能保证原子性,故可能是不安全的。
上面提到了可以用 volatile 和 synchronized 来保证有序性。除此之外,JVM 还规定了先行发生原则,让一个操作无
需控制就能先于另一个操作完成。
1. 单一线程原则
2. 管程锁定规则
3. volatile 变量规则
4. 线程启动规则
5. 线程加入规则
6. 线程中断规则
7. 对象终结规则
8. 传递性
以下分别图示:
1、单一线程原则 :
在一个线程内,在程序前面的操作先行发生于后面的操作。
2. 管程锁定规则 :
一个 unlock 操作先行发生于后面对同一个锁的 lock 操作。
3. volatile 变量规则
对一个 volatile 变量的写操作先行发生于后面对这个变量的读操作。
4. 线程启动规则
Thread 对象的 start() 方法调用先行发生于此线程的每一个动作。
5. 线程加入规则
Thread 对象的结束先行发生于 join() 方法返回。
6. 线程中断规则
对线程 interrupt() 方法的调用先行发生于被中断线程的代码检测到中断事件的发生,可以通过 interrupted() 方法检测到是否有中断发生。
7. 对象终结规则
一个对象的初始化完成(构造函数执行结束)先行发生于它的 fifinalize() 方法的开始。
8. 传递性
如果操作 A 先行发生于操作 B,操作 B 先行发生于操作 C,那么操作 A 先行发生于操作 C。
Over......