共享模型之内存
JMM
java内存模型,定义了主存、工作内存抽象概念,底层对应着CPU寄存器、缓存、硬件内存、CPU指令优化等
体现
- 原子性–保证指令不会受到线程上下文切换的影响
- 可见性–保证指令不会受到cpu缓存的影响
- 有序性–保证指令不会受到CPU指令并行优化的影响
可见性
退不出的循环
static boolean run = true;
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(()->{
while(run){
// ....
}
});
t.start();
sleep(1);
run = false; // 线程t不会如预想的停下来
}
-
初始状态,t线程从主存中读取了run值到工作内存
-
t线程需要频繁从主存中读取run的值,JIT编译器会将run的值缓存到自己工作内存中的高速缓存中,减少对主存中run的访问,提高效率
-
当主线程修改了run的值,并同步到主存,而t线程仍是从自己的工作内存中的高速缓存读取这个变量的值,结果永远是旧值
volatile(易变关键字)
可以用来修饰成员变量和静态成员变量,可以避免线程从自己的工作内存中查找变量的值,必须到主存中获取它的值,线程操作volatile都是直接操作主存
但是不能保证原子性,仅用在一个写进程,多个读进程的情况
如果在前面示例的死循环中加入 System.out.println() 会发现即使不加 volatile 修饰符,线程 t 也能正确看到对 run 变量的修改,为什么?
因为其内部包含了synchronized 的使用