学习笔记(37):第1章 分布式基础之并发编程-探索线程安全性背后的本质之volatile 02

立即学习:https://edu.csdn.net/course/play/29000/405251?utm_source=blogtoedu

1、如何才能 CPU层面的优化失效来解决可见性问题和指令重排序问题呢?

那就是实时让缓存失效,从内存中读取数据=》也就是搞一下 内存屏障

内存屏障作用就是 不允许指令重排序,禁用高速缓存

加入volatile关键字,就会增加这个内存屏障

2、java内存模型(JMM) 定义了共享内存中,多线程读写的规范,解决了不同平台的差异化,提供一个统一的线程安全性的一致性模型,提供了可见性和有序性问题的解决方案

3、开发的指令到执行的指令会经过三步优化

源代码=》编译器优化重排序=》(CPU层面)指令级并行重排序=》(CPU层面)内存系统重排序=》最终执行指令排序

这些优化就会造成可见性问题,所以硬件层面就又提供了内存屏障来解决这个问题,软件层面提供了调用内存屏障的方法

4、综上 volatile是如何解决可见性问题的呢?

提供了一个防止内存指令重排序的机制和通过内存屏障机制去解决可见性问题

5、那么volatile在什么情况下使用呢?

存在多个线程访问、并发访问的可能性,那么需要加volatile来保证可见性

6、引申问题 单例模式中 双重检查锁判断 instance==null

A a;

a=new A();

new A() 在操作系统中 是三个指令 会有重排序问题 所以 需要加 volatile关键字

static volatile A a;

a=new A();

7、Happens-Before模型-软件层面的一种自身解决可见性问题的模型

A Happens Before B,并不是A一定运行在B之前,而是 A的结果值对B可见

什么情况下会存在这个模型?

(1)程序顺序规则(as-if-serial)

不能改变程序的执行结果(单线程环境下,执行结果不变)

依赖问题,如果两个指令存在依赖关系,不允许重排序

int a=0;int b=1; int c=a*b;

(2)传递性规则

A Happens Before B;

B Happens Before C;

A的结果一定对C可见

(3)volatile变量规则

volatile修饰变量的写操作,一定hanppens-before 后续对vaolatile变量的读操作,因为内存屏障机制来防止指令重排序

(4)监视器锁规则

 一个锁的释放操作,一定hanppens-before 后续其他线程对应锁的操作  其实就是synchronized();本身加锁,所以在所有线程中是可见的,不可重排序的

(5)start规则

int x=10;

Thread t1=new Thread(()->{读取 x值,一定是20}); 

x=20;

t1.start();

start之前的操作一定 hapens-before 线程中的任意操作

(6) join规则

Thread.join();是一种阻塞行为

猜你喜欢

转载自blog.csdn.net/qq_28500837/article/details/112978549