happen-before原则与JMM内存模型
happen-before原则
happen-before是JMM最核心的概念,所以在了解happen-before原则之前,首先需要了解java的内存模型。
JMM内存模型
java内存模型是共享内存的并发模型,线程之间主要通过读-写共享变量来完成隐式通信。java中的共享变量是存储在内存中的,多个线程由其工作内存,其工作方式是将共享内存中的变量拿出来放在工作内存,操作完成后,再将最新的变量放回共享变量,这时其他的线程就可以获取到最新的共享变量。
从横向去看看,线程A和线程B就好像通过共享变量在进行隐式通信。这其中有很有意思的问题,如果线程A更新后数据并没有及时写回到主存,而此时线程B读到的是过期的数据,这就出现了 “脏读” 现象。
为避免脏读,可以通过同步机制(控制不同线程间操作发生的相对顺序)来解决或者通过volatile关键字使得每次volatile变量都能够强制刷新到主存,从而对每个线程都是可见的。
重排序
在执行程序时,为了提高性能,编译器和处理器常常会对指令进行重排序。一般重排序可以分为如下三种:如图,1属于编译器重排序,而2和3统称为处理器重排序。
这些重排序会导致线程安全的问题,一个很经典的例子就是DCL问题。JMM的编译器重排序规则会禁止一些特定类型的编译器重排序;针对处理器重排序,编译器在生成指令序列的时候会通过插入内存屏障指令来禁止某些特殊的处理器重排序。
(1)编译器优化的重排序。编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序;
(2)指令级并行的重排序。现代处理器采用了指令级并行技术来将多条指令重叠执行。如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序;
(3)内存系统的重排序。由于处理器使用缓存和读/写缓冲区,这使得加载和存储操作看上去可能是在乱序执行的。
举个例子:
double pi= 3.14;double r=1.0;double area=pi*r*r;
由于A,B之间没有任何关系,对最终结果也不会存在关系,它们之间执行顺序可以重排序。因此可以执行顺序可以是A->B->C或者B->A->C执行最终结果都是3.14,即A和B之间没有数据依赖性。
什么是happen-before
JMM可以通过happens-before关系向程序员提供跨线程的内存可见性保证(如果A线程的写操作a与B线程的读操作b之间存在happens-before关系,尽管a操作和b操作在不同的线程中执行,但JMM向程序员保证a操作将对b操作可见)。
具体的定义为:
1)如果一个操作happens-before另一个操作,那么第一个操作的执行结果将对第二个操作可见,而且第一个操作的执行顺序排在第二个操作之前。
2)两个操作之间存在happens-before关系,并不意味着Java平台的具体实现必须要按照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()(启动线程B),那么A线程的ThreadB.start()操作happens-before于线程B中的任意操作。
(6)Join()规则:如果线程A执行操作ThreadB.join()并成功返回,那么线程B中的任意操作happens-before于线程A从ThreadB.join()操作成功返回。
(7)程序中断规则:对线程interrupted()方法的调用先行于被中断线程的代码检测到中断时间的发生。
(8)对象finalize规则:一个对象的初始化完成(构造函数执行结束)先行于发生它的finalize()方法的开始。
利用程序顺序规则(规则1)存在三个happens-before关系:
A happens-before B;
B happens-before C;
A happens-before C。
这里的第三个关系是利用传递性进行推论的。这里的第三个关系是利用传递性进行推论的。
A happens-before B,定义1要求A执行结果对B可见,并且A操作的执行顺序在B操作之前,但与此同时利用定义中的第二条,A,B操作彼此不存在数据依赖性,两个操作的执行顺序对最终结果都不会产生影响,在不改变最终结果的前提下,允许A,B两个操作重排序,即happens-before关系并不代表了最终的执行顺序。
happen-before原则与JMM内存模型相关推荐
- 最新详细的JMM内存模型(三天熬夜血肝)
知识图谱 前言 网上并发以及JMM部分的内容大部分都特别的乱,也不好整理.花了三四天时间才整理了一篇,有些概念的东西,是需要了解的,也标注出来了. 标注:在学习中需要修改的内容以及笔记全在这里 www ...
- JMM内存模型如何为并发保驾护航
一.为何引入JMM 每个处理器在执行任务时,不可能单靠"计算"就可以完成所有任务,处理器至少需要和内存交互,进行读取运算数据.存储运算结果等,这个I/O操作是很难消除掉的.但由于计 ...
- JUC多线程:JMM内存模型与volatile内存语义
一.JMM 内存模型: 1.什么是 JMM 内存模型: Java 内存模型是 Java 虚拟机定义的一种多线程访问 Java 内存各个变量的访问规范,主要围绕如何解决并发过程中的原子性.可见性.有序性 ...
- 用volatile的视角,来打开JMM内存模型
文章目录 [引言] 1. 多核并发缓存架构 CPU缓存 JMM内存模型简介 2. JMM内存模型验证 volatile验证内存模型 JMM内存模型8大原子操作 3. JMM缓存不一致问题 总线加锁 M ...
- 深入理解并发内存模型||JMM与内存屏障||多核并发缓存架构 ||JMM内存模型||volatile 关键字的作用 ||JMM 数据原子操作||JMM缓存不一致的问题
深入理解并发内存模型||JMM与内存屏障 多核并发缓存架构 JMM内存模型 volatile 关键字的作用 JMM 数据原子操作 JMM缓存不一致的问题
- java——JMM内存模型
目录 简介 三大特性 volatile关键字 简介 JMM内存模型,也称为Java多线程内存模型.它和cpu缓存模型类似,是基于cpu缓存模型来建立. cpu缓存模型: java内存模型: 当Java ...
- JMM内存模型详解(一)
本文开始死磕JMM(Java内存模型)由于知识点较多,分来写 该文为JMM第一篇 技术往往是枯燥的,本文文字较多 1. JMM是什么? 其实JMM很好理解,我简单的解释一下,在Java多线程中我们经常 ...
- JMM内存模型 多线程三大特性
本文目录 1.JMM 内存模型 1.主内存 2.工作内存 3.JMM 线程操作内存的两条基本规定 4.JMM 模型八大内存交互指令 5.JMM 模型内存交互操作 6.JMM 模型内存同步规则 2.多线 ...
- 深入理解JMM内存模型
目录 一.JMM内存模型产生的背景? 二.什么是JMM内存模型? 三.JMM内存模型用来解决什么问题? 四.JMM内存模型与JVM内存模型有什么关系? 一.JMM内存模型产生的背景? JMM(Java ...
- Java并发-JMM内存模型
1.线程与JVM 2.JVM内存模型与Java内存模型的区别 3.硬件内存架构与Java内存模型 4.Java内存模型对并发特征的保证 一.基本概念 程序:代码,完成某一件任务,代码序列(静态的概念) ...
最新文章
- 每日一皮:我以为的工作量 VS 实际上的工作量
- 零基础自学python的建议-经验之谈——大学时候,我是如何零基础自学Python的?...
- js/jquery中实现图片轮播
- 1、python的基础
- 视频技术详解:RTMP H5 直播流技术解析
- 论文浅尝 | 用于开放领域的问题生成
- 比较牛逼的答题卡扫描算法
- [C++][代码库]Vector3空间向量类
- Leetcode 513 javascript
- per_cpu机制的详解
- 更改Android 默认键盘映射值
- 怎么把录音导入库乐队_库乐队导入电脑版 苹果库乐队怎么导入歌
- HDU1728 BFS
- 计算机不认2t移动硬盘,win7系统无法识别2T希捷的硬盘的解决方法
- 计算机win10无法打开小键盘,小编告诉你win10开机小键盘不自动开启的解决伎俩...
- 阿里云建站备案必要性
- 店铺如何提升流量,抢占先机
- 【论文笔记】 Reinforcement-Learning-Guided Source Code Summarization using Hierarchical Attention
- 无损数据压缩 Lossless Compression
- 斗地主农民手牌的58684015种可能性