JUC并发编程—共享模型之内存管理解析

本文详细探讨了Java内存模型(JMM)的概念,包括内存交互、可见性、原子性和有序性,以及如何通过volatile和happens-before原则确保多线程环境下的数据一致性。同时涉及CPU缓存和解决方法,以及对内存顺序规则、监视器锁规则等的理解。
摘要由CSDN通过智能技术生成

5、共享模型之内存管理

5.1 Java 内存模型

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

JMM 作用:屏蔽各种硬件和操作系统的内存访问差异,实现让 Java 程序在各种平台下都能达到一致的内存访问效果,

规定了线程和内存之间的一些关系

运作流程

概念区分

内存交互

三大特性

可见性、原子性

5.2 可见性

含义:

是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值

由于缓存的存在,线程持有的是共享变量的副本,无法感知其他线程对于共享变量的更改,导致读取的值不是最新的。但是 final 修饰的变量是不可变的,就算有缓存,也不会存在不可见的问题

main 线程对 run 变量的修改对于 t 线程不可见,导致了 t 线程无法停止:

1. 初始状态, t 线程刚开始从主内存读取了 run 的值到工作内存。

因为 t 线程要频繁从主内存中读取 run 的值,JIT 编译器会将 run 的值缓存至自己工作内存中的高速缓存中,减少对主存中 run 的访问,提高效率

1 秒之后,main 线程修改了 run 的值,并同步至主存,而 t 是从自己工作内存中的高速缓存中读取这个变量的值,结果永远是旧值

1、CPU 缓存结构原理

2、CPU 缓存读

3. CPU 缓存一致性

解决方法

5.3 有序性

说明:

在本线程内观察,所有操作都是有序的;在一个线程观察另一个线程,所有操作都是无序的,无序是因为发生了指令重排序

CPU 的基本工作是执行存储的指令序列,即程序,程序的执行过程实际上是不断地取出指令、分析指令、执行指令的过程,为了提高性能,编译器和处理器会对指令重排,一般分为以下三种:

指令级并行原理

解决方法

volatile 修饰的变量,可以禁用指令重排

原理之 volatile

1. 如何保证可见性

2. 如何保证有序性

3. double-checked locking 问题

happens-before原则

happens-before 规定了对共享变量的写操作对其它线程的读操作可见,它是可见性与有序性的一套规则总结

抛开以下 happens-before 规则,JMM 并不能保证一个线程对共享变量的写,对于其它线程对该共享变量的读可见

都是针对成员变量和静态成员变量

1 程序顺序规则:

一个线程中的每个操作,happens-before于该线程中的任意后续操作。

2 监视器锁规则:

对于一个锁的解锁,happens-before之后是对这个锁的加锁。

3 volatile变量规则:

对一个volatile域的写,happens-before之后是对volatile域的读。

4 传递性:

如果A happens-before B,B happens-before C,那么A happens-before C。

5 start()规则:

如果线程A执行操作ThreadB•start(),那么线程A的ThreadB.start()happens-before线程B中的任意操作。

6 join()规则

如果线程A执行操作ThreadB.join()并且成功返回,那么线程B中的任意操作于happens-before线程A从ThreadB.join()操作成功返回。

注意⚠️ 两个操作之间有happens-before的关系,不一定是A操作在B操作之前执行。如果重排序之后执行的结果,与按照happens-before关系来执行的结果一致,那么这种重排序并不非法。

简单来说如果前一个操作happens-before后一个操作,只需要前一个操作执行的结果对后一个操作可见,而且前一个操作的顺序在第二个操作之前。这是JMM对程序员做出的保证。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值