JMM
- 主内存和工作内存
- 主内存
- 包括:实例字段、静态字段、和构成数组对象的元素;但不包括局部变量和方法参数,因为他们是线程私有的
- 所有变量都存储在主内存
- 工作内存是线程使用到的变量的主内存的副本,线程对变量的操作必须在工作内存中进行
- 主内存
- 内存交互操作
- lock
- unlock
- read
- load
- use
- assign
- store
- write
- 操作规则:
volatile ——jvm P362-jmm
- 变量定义为volatile之后具备两种特性 :
- 保证变量对所有线程的可见性 不保证原子性
- 禁止指令重排
- 实现:
- 可见性 :在对volatile变量赋值之后,会多执行一个lock语句,使得本cpu的cache写入内存,写入操作会使别的cpu无效化其cache,需要使用该变量时,需要重写从主存读取,进而实现可见性
- 禁止指令重排 :lock使本cpu的cache写入内存,需要保证lock前的操作执行完毕(因为指令重排不能影响程序运行结果),所以可以保证lock前的操作发生在lock后的操作前。
- volatile 规则:
- 使用变量前,需要从主存刷新,保证可以看到其他线程的修改
- 修改变量后,立即写回主存,保证可以让其他线程看到
- 禁止指令重排 (原文《深入理解jvm》P372 我看不懂)
- 针对64位基本类型——long, double,允许jvm不保证其load, store, read, write操作的原子性。
原子性,可见性,有序性
——jmm是围绕这并发过程中如何处理这三个特性建立起来的,以下是哪些操作可以实现三个特性
- 原子性
- 定义
- 实现:jmm层次:lock,unlock;字节码指令monitorenter,monitorexit;关键字synchronized
- 可见性
- 定义
- 实现:volatile,synchronized,final
- synchronized 使用lock和unlock实现 unlock之前须将变量写回内存
- final 假如this引用未逃逸(this引用逃逸可能使其他线程访问到初始化了一半的对象),final因为不可变所以工作内存中的副本和主存相同,可以保证可见性
- 有序性
- 定义
- 实现
- volatile禁止指令重排
- synchronized 变量同时只允许一条线程lock,而单一线程的所有操作尽管会重排序,但不影响结果,可以认为有序。
先行发生原则
- 程序次序规则:一个线程内,按按照代码顺序执行
- 管程锁定规则:同一个锁的unlock先行与后面的lock
- volatile变量规则:对volatile变量的写操作先行发生与后面的读操作
- 线程启动规则:thread的start方法先行发生于此线程的每一个动作
- 线程终止规则:线程的所有操作都先行发生于对此线程的终止检测
- 线程中断规则:对线程的interrupt操作先行发生于检测到线程中断的发生
- 对象终结规则:对象的初始化完成先行于它的finalize的开始
- 传递性:A先于B,B先于C ,则A先于C