计算机的运算速度与它的存储和通信子系统速度差距过大,为了压榨计算机性能,多任务处理才诞生。
内存模型是一种缓存一致性协议。
1 | A1[处理器] --> B1(高速缓存) |
Java内存模型JMM
JMM屏蔽各种硬件和操作系统的内存访问差异,目的是定义各个变量(实例变量、类变量、数组对象元素,不含有局部变量,因为线程私有)的访问规则。
0x00 主内存和工作内存
一些规则。
- 所有的变量(实例变量、类变量、数组对象元素,不含有局部变量,因为线程私有)都存储在主内存。
- 线程有自己的工作内存。
- 线程对变量的所有操作(读取,赋值)必须在
工作内存
中进行,不能直接读写主内存的变量。 - 线程间变量的传递需要通过主内存。
1 | A1[线程] --> B1(工作内存) |
0x01 内存交换操作
作用于主内存的有(lock、unlock、read、write),作用于工作内存的有(load、use、assign、store)。
- lock:把变量标识为线程独占状态。
- unlock:把处于锁定状态的变量释放出来,以便其他线程继续使用。
- read:把变量的值从主内存cp到工作内存中,以便之后的load动作使用。
- load:把read动作得到的值加载到工作内存中的变量副本中。
- use:把变量的值从工作内存传递到执行引擎。
- assign:把执行引擎返回的值赋给工作内存的变量。
- store:把工作内存的值传递给主内存,以便之后的write动作使用。
- write:把store动作得到的值写入主内存变量中。
交换八大规则,这八大规则严谨而又繁琐,
使用等效判定原则--先行发生原则
。
- read和load、store和write必须成对出现(中间可以有其他动作),就是说,不允许变量从主内存读取后工作内存不接受,不允许变量从工作内存写回主内存不接受。
- 变量在工作内存改变后,必须把该变化同步到主内存。
- 不允许线程在未发生assign动作的前提下把数据从工作内存写回主内存。
- 新的变量只能从主内存诞生。
- 一个变量在同一时间只能被一条线程进行lock操作,但同意线程可lock多次。
- 对变量进行lock操作,会清空工作内存中该变量的值。
- 不允许对未进行lock的线程进行unlock操作。
- 对变量进行unlock操作前,必须把值同步回主内存。
0x10 volatile变量特殊规则
volatile保证两个特性:
只
保证变量对所有线程的可见性;禁止指令重排序。
- 线程可见性:一条线程改变了变量值,新值对其他线程时立即可见的。
- 指令重排序:保证执行的最终结果正确,不保证变量赋值操作的顺序和代码中一致。
在
不符合
以下规则是,需要通过加锁保证原子性,不能通过volatile。
- 运算结果不依赖当前值,或者保证只有一个线程修改变量值。
- 变量不需要于其他变量参与不变约束。
0x11 先行发生原则
A操作先行发生于B操作,那么A操作参数的影响会被B操作观察到。时间先后顺序和先行发生没有关联。
- 程序次序规则(Program Order):在同一线程内,写在前面的操作先行发生于之后的操作。
- 管程锁定规则(Monitor Lock):一个unlock操作先行发生于时间上后面对同一个锁的lock操作。
- volatile变量规则(Volatile Variable):volatile变量的写操作先行发生于时间上后面对该变量的读操作。
- 线程启动规则(Thread Start):Thread对象的start方法先行发生于线程的每一个动作。
- 线程终止规则(Thread Termination):线程中所有的操作先行发生有线程的终止检测。
- 线程中断规则(Thread Interruption):对线程的interrupt方法调用先行发生于被中断线程的代码检测到该中断事件的发生。
- 对象终止原则(Finalizer):一个对象的初始化完成先行发生于finalize方法的开始。
- 传递性(Transitivity)