java并发day03 JMM、可见性、 有序性 、volatile底层原理 、happens-before

JMM

JMM 即 Java Memory Model,它定义了主存、工作内存抽象概念,底层对应着 CPU 寄存器、缓存、硬件内存、CPU 指令优化等。

JMM 体现在以下几个方面

原子性 - 保证指令不会受到线程上下文切换的影响
可见性 - 保证指令不会受 cpu 缓存的影响
有序性 - 保证指令不会受 cpu 指令并行优化的影响

可见性

保证线程不会受到缓存的影响。

解决方法:

volatile(易变关键字)

它可以用来修饰成员变量和静态成员变量,他可以避免线程从自己的工作缓存中查找变量的值,必须到主存中获取它的值,线程操作 volatile变量都是直接操作主存。
可见性,它保证的是在多个线程之间,一个线程对 volatile 变量的修改对另一个线程可见, 不能保证原子性,仅用在一个写线程,多个读线程的情况
synchronized 语句块既可以保证代码块的原子性,也同时保证代码块内变量的可见性。但缺点是synchronized 是属于重量级操作,性能相对更低

有序性

保证指令不会受 cpu 指令并行优化的影响
JVM 会在不影响正确性的前提下,可以调整语句的执行顺序,这就是指令重排,多线程下指令重排会影响正确性。

指令重排的底层

每条指令都可以分为: 取指令 - 指令译码 - 执行指令 - 内存访问 - 数据写回 这 5 个阶段

instruction fetch (IF) 取指令
instruction decode (ID) 指令译码
execute (EX) 执行指令
memory access (MEM) 内存访问
register write back (WB) 数据写回

在不改变程序结果的前提下,这些指令的各个阶段可以通过重排序和组合来实现指令级并行。 现代 CPU 支持多级指令流水线,例如支持同时执行
取指令 - 指令译码 - 执行指令 - 内存访问 - 数据写回 的处理器,就可以称之为五级指令流水线。这时 CPU可以在一个时钟周期内,同时运行五条指令的不同阶段。本质上,流水线技术并不能缩短单条指令的执行时间,但它变相地提高了指令地吞吐率。

解决方法

volatile 修饰的变量,可以禁用指令重排
防止之前的代码被重排序,写屏障

volatile底层原理

volatile 的底层实现原理是内存屏障

对 volatile 变量的写指令后会加入写屏障
对 volatile 变量的读指令前会加入读屏障

内存屏障Memory Barrier(Memory Fence)

可见性
写屏障(sfence)保证在该屏障之前的,对共享变量的改动,都同步到主存当中
读屏障(lfence)保证在该屏障之后,对共享变量的读取,加载的是主存中最新数据

有序性
写屏障会确保指令重排序时,不会将写屏障之前的代码排在写屏障之后
读屏障会确保指令重排序时,不会将读屏障之后的代码排在读屏障之前

volatile缺陷

写屏障仅仅是保证之后的读能够读到最新的结果,但不能保证读跑到它前面去
有序性的保证也只是保证了本线程内相关代码不被重排序
所以volatile不能解决共享变量在多线程上下文切换的原子性问题

在这里插入图片描述

double-checked locking问题

在这里插入图片描述

在这里插入图片描述

double-checked locking问题产生的原因在于构造方法还未执行完毕就被读取。
getstatic 这行代码在 monitor控制之外,它就像之前举例中不守规则的人,可以越过 monitor 读取INSTANCE 变量的值
这时 t1 还未完全将构造方法执行完毕,如果在构造方法中要执行很多初始化操作,那么 t2 拿到的是将是一个未初始化完毕的单例

double-checked locking解决

指令重排序的问题。

在这里插入图片描述

happens-before

happens-before 规定了对共享变量的写操作对其它线程的读操作可见,它是可见性与有序性的一套规则总结,抛开以下happens-before 规则,JMM 并不能保证一个线程对共享变量的写,对于其它线程对该共享变量的读可见

1、线程解锁之前对变量的写,对于接下来加锁的其它线程对该变量的读可见
2、线程对 volatile 变量的写,对接下来其它线程对该变量的读可见
3、线程 start 前对变量的写,对该线程开始后对该变量的读可见
4、线程结束前对变量的写,对其它线程得知它结束后的读可见(比如其它线程调用 t1.isAlive() 或 t1.join()等待它结束)
5、线程 t1 打断 t2(interrupt)前对变量的写,对于其他线程得知 t2 被打断后对变量的读可见(通过t2.interrupted 或 t2.isInterrupted)
6、对变量默认值(0,false,null)的写,对其它线程对该变量的读可见
7、具有传递性,如果 x hb-> y 并且 y hb-> z 那么有 x hb-> z

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

halulu.me

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值