并发编程(十一):共享模型之内存
2020-04-19 本文已影响0人
codeMover
Java内存模型
JVM即Java Memory Model,定义了主存、工作内存抽象概念,底层对应CPU寄存器、缓存、硬件内存、CPU指令优化等。
- 原子性:保证指令不会受到线程上下文切换的影响
- 可见性:保证执行不会受cpu缓存的影响
- 有序性:保证指令不会受cpu执行并行优化的影响
原子性
- synchronized
- ReentrenLock
可见性
- volatile:可以修饰成员变量和静态成员变量,可以避免从自己的工作缓存中查找变量的值,必须到主存中获取变量的值,线程操作volatile变量都是直接操作内存。
- synchronized:保证可见性
- 保证锁对象,共享变量的修改读取放在锁的同步块内,保证可见性
- synchronized语句块既可以保证代码块的原子性也能保证代码块内的变量可见性,但是synchronized属于重量级操作,性能相对低
有序性
JVM会在不影响正确性的前提下,可以调整语句的执行顺序
- 现在CPU支持多级指令流水线,CPU在一个周期内,可以划分执行不同阶段指令。本质上流水线技术并不能缩短单条指令执行顺序,但是一个时间周期内可以提高执行吞吐率。
- 在不改变程序执行结果的前提下,指令的各个阶段可以通过重排序和组合来实现指令级并行。
volatile原理
volatile的底层实现原理是内存屏障 memory barrier
- 对volatile变量的写指令后会加入写屏障
- 对volatile变量的读指令前会加入读屏障
可见性
- 写屏障保证在该屏障之前的,对于共享变量的改动,都同步到主存中
- 读屏障保证在该屏障之后,对共享变量的读取加载时的主存中的最新数据
有序性
- 写屏障会保证指令重排时,不会将写屏障之前的代码排在写屏障之后
- 读屏障会保证指令重排时,不会将读屏障之后的代码排在读屏障之前
- 有序性仅仅是在同一线程有序
原子性
- volatile不能保证原子性,仅能够保证之后读能读到最新数据,多线程不能保证原子性
hanppens-before
happens-before规定了贡献该变量的写操作对其他线程的读操作可见
- synchronized
- volatile
- 在线程start之前的写,对于start后读可见
- 线程结束之前会将工作内存的值同步到主内存中
- 对变量默认值的写,对其他线程的读可见
- 传递性