多线程篇(可见性 原子性 有序性(有序性))(持续更新迭代)

news2024/12/22 19:16:50

目录

一、指令重排序(并发编程之美)

二、指令重排序(百度)

1. 为什么需要指令重排序

2. 什么是指令重排序

3. 指令重排序分类

3.1. 编译器优化重排序

3.2. 指令级并行的重排序

3.3. 内存系统的重排

4. 指令重排序规范

4.1. as-if-serial 规范

4.2. happens-before 规范

happens-before 先行发生原则 适用场景

5. 重排序对于流水线的意义


一、指令重排序(并发编程之美)

Java 内存模型允许编译器和处理器对指令重排序以提高运行性能,

并且只会对不存在数据依赖性的指令重排序。

在单线程下重排序可以保证最终执行的结果与程序顺序执行的结果一致,但是在多线程下就会存在问题。

下面看一个例子:

加载...

在如上代码中,变量 c 的值依赖a和b的值,所以重排序后能够保证(3)的操作在(2)(1)之后,

但是(1)(2)谁先执行就不一定了,这在单线程下不会存在问题,因为并不影响最终结果。

重排序在多线程下会导致非预期的程序执行结果,而使用volatile 修饰 ready 就可以避免重排序和内

存可见性问题。

写 volatile 变量时,可以确保 volatile 写之前的操作不会被编译器重排序到 volatile 写之后。

读 volatile 变量时,可以确保 volatile 读之后的操作不会被编译器重排序到 volatile 读之前。

二、指令重排序(自我整理)

1. 为什么需要指令重排序

其实说到底都是源于对性能的优化,CPU运行效率 相比缓存、内存、硬盘IO之间效率有着指数级的差

别,CPU作为系统的宝贵资源,那么如何更好的优化和利用这个资源就能提升整个计算机系统的性

能。

其实指令重排序就是一种来源于生活的优化思想,这种思想在生活中处处可见,就像平常咱们做菜,

咱们会选择在炒第一个菜的同时就在洗第二个菜了, 咱们会把熟得最慢的菜放到最开始(比如煲

汤),因为在等待这些菜熟的过程中(IO等待)咱们(CPU)还可以做其它事情,这就是一种时间上的

优化,在计算机领域也是一样,它也会根据指令的类别做一些优化,目的就是把CPU的资源利用起

来,这样就能就能提升整个计计算机的效率。

2. 什么是指令重排序

java语言规范规定JVM线程内部维持顺序化语义。

即只要程序的最终结果与它顺序化情况的结果相等,那么指令的执行顺序可以与代码顺序不一致,此

过程叫指令的重排序。

3. 指令重排序分类

在执行程序时为了提高性能,编译器和处理器常常会对指令做重排序。

3.1. 编译器优化重排序

编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序

3.2. 指令级并行的重排序

现代处理器采用了指令级并行技术(Instruction-Level Parallelism, ILP)来将多条指令重叠执行。

如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序。

3.3. 内存系统的重排

由于处理器使用缓存和读/写缓冲区,这使得加载和存储操作看上去可能是在乱序执行。

重排序流如下图所示:

从java源代码到最终实际执行的指令序列,会分别经历下面三种重排序:

上述的1属于编译器重排序,2和3属于处理器重排序。

这些重排序都可能会导致多线程程序出现内存可见性问题。

对于编译器,JMM的编译器重排序规则会禁止特定类型的编译器重排序

(不是所有的编译器重排序都要禁止)。

对于处理器重排序,JMM的处理器重排序规则会要求java编译器在生成指令序列时,插入特定类型的

内存屏障(memory barriers,intel称之为memory fence)指令,通过内存屏障指令来禁止特定类型

的处理器重排序(不是所有的处理器重排序都要禁止)。

JMM属于语言级的内存模型,它确保在不同的编译器和不同的处理器平台之上,

通过禁止特定类型的编译器重排序和处理器重排序,为程序员提供一致的内存可见性保证。

4. 指令重排序规范

4.1. as-if-serial 规范

单个线程中, 指令的重排 , 不能影响程序的执行结果 ;

可以重排的情况 : 对于下面代码 , 两条指令顺序颠倒 , 执行结果相同 , 可以进行指令重排 ;

int a = 0;
int b = 10;

不可以进行重排的情况 : 对于下面的代码 , 两条指令如果上下颠倒 , 结果不同 , 不可以进行指令重排 ;

int a = 0;
int b = a;

不管怎么重排序,程序的执行结果不能被改变,编译器,runtime 和处理器都必须遵守as-if-serial语

义。即编译器和处理器在重排序时,会遵守数据依赖性,编译器和处理器不会改变存在数据依赖关系

的两个操作的执行顺序。

为了遵守as-if-serial语义,编译器和处理器不会对存在数据依赖关系的操作做重排序,因为这种重排

序会改变执行结果。但是,如果操作之间不存在数据依赖关系,这些操作可能被编译器和处理器重排

序。

as-if-serial语义把单线程程序保护了起来,遵守as-if-serial语义的编译器,runtime 和处理器共同为编

写单线程程序的程序员创建了一个

幻觉:单线程程序是按程序的顺序来执行的。

as-if-serial语义使单线程程序员无需担心重排序会干扰他们,也无需担心内存可见性问题。

4.2. happens-before 规范

先行发生原则 。

happens-before 先行发生原则 :A happens-before B,A 先于 B 发生 , 先 A 后 B ;

Java 虚拟机在编译时和运行时 , 会对 JVM 指令进行重排优化 , 很明显 , 指令重排会对线程并发产生影

响 ;为了保证并发编程的安全性,这里规定了一些场景下 , 禁止在这些场景中 使用 指令重排 ;

happens-before 先行发生原则 适用场景

程序次序原则

在程序内 , 按照代码书写的执行顺序 , 前面的代码先执行 , 后面的代码后执行 ; 时间上 靠前 的操作先

于时间上靠后 的操作执行。

管程锁规则

不论是单线程还是多线程 , 线程 A 解锁后 , 线程 B 获取该锁 , 可以看到线程 A 的操作结果 ;

解锁的操作先于加锁的操作 ; 线程 B 要加锁 , 必须等待线程 A 解锁完毕才可以 ;

volatile 规则

volatile 关键字修饰的变量 , 线程 A 对该变量的写操作 先于 线程 B 读取该变量的操作 ,

线程 A 对该变量的写操作的结果对于线程 B 一定可见 ;

线程启动规则

线程的start()方法先于它的每一个动作,即如果线程A在执行线程B的start方法之前修改了共享变量的

值,那么当线程B执行start方法时,线程A对共享变量的修改对线程B可见。

线程终止规则

线程的所有操作先于线程的终结,Thread.join()方法的作用是等待当前执行的线程终止。

假设在线程B终止之前,修改了共享变量,线程A从线程B的join方法成功返回后,线程B对共享变量的

修改将对线程A可见。

传递性

happens-before 规则具有传递性 ;如果 A happens-before B 和 B happens-before C ,则 A happens-

before C ;

线程中断规则

对线程 interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生,可以通过

Thread.interrupted()方法检测线程是否中断。

对象终结规则

对象的创建先于对象的终结,, 创建就是调用构造函数 , 终结就是调用finalize()方法

只要符合上述规则 , 不需要进行同步 , 就可以成立 ;

通过 " happens-before 先行发生原则 " 可以判定两个线程的操作 , 是否有发生冲突的可能 ;

5. 重排序对于流水线的意义

现代CPU几乎都采用流水线机制加快指令的处理速度,一般来说,一条指令需要若干个CPU时钟周期

处理,而通过流水线并行执行,可以在同等的时钟周期内执行若干条指令,具体做法简单地说就是把

指令分为不同的执行周期,例如读取、寻址、解析、执行等步骤,并放在不同的元件中处理,同时在

执行单元EU中,功能单元被分为不同的元件,例如加法元件、乘法元件、加载元件、存储元件等,可

以进一步实现不同的计算并行执行。流水线架构决定了指令应该被并行执行,而不是在顺序化模型中

所认为的那样。重排序有利于充分使用流水线,进而达到超标量的效果。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2103647.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【AI工作流】未来的我将何去何从?亲身感受!

在这个瞬息万变的科技时代,人工智能(AI)已经成为推动各行各业变革的核心动力。随着AI技术的不断进步,工作流程的智能化正在悄然改变我们的生活和工作方式。那么,未来的我将何去何从?这是一个值得深思的问题…

揭秘!焦虑症背后的隐形推手:气血不足,你了解多少?

在这个快节奏、高压力的时代,焦虑症似乎成了许多人心头挥之不去的阴霾。失眠、心悸、易怒、持续担忧……这些症状不仅影响着我们的生活质量,更在无形中侵蚀着我们的身心健康。然而,你是否知道,这些看似心理层面的困扰,…

springboot高校实验室教学管理系统的设计和实现

基于springbootvue高校实验室教学管理系统的设计和实现(源码L文ppt)4-045 4 系统总体设计 此次高校实验室教学管理系统通过springboot框架。springboot适合快速构建Web应用。springboot将B/S设计模式中的视图分成了View模块和Template模块两部分,将动态的逻辑处理…

如何获取本地时区名称:JavaScript 实用技巧

如何获取本地时区名称:JavaScript 实用技巧 在现代 web 开发中,处理日期和时间是一个常见的需求。尤其是在涉及到用户的本地时间时,正确获取时区信息显得尤为重要。在这篇博客中,我们将探讨如何使用 JavaScript 获取本地时区名称…

数学基础(四)

一、特征值与特征向量 特征空间: 特征向量的应用: 特征值表达了重要程度且和特征向量所对应,那么特征值大的就是主要信息了,基于这点我们可以提供各种有价值的信息。 二、SVD矩阵分解 基变换: 特征值分解&#xff…

红黑树的插入 C++

红黑树与二叉搜索树类似 它在每个节点增加了一个存储位记录节点的颜色,可以是RED,也可以是BLACK;通过任意一条从根到叶子简单路径上颜色的约束,红黑树保证最长路径不超过最短路径的二倍,因而近似平衡(最短路径就是全黑…

zlib压缩解压文件

zlib_utils.h #pragma once#include <Windows.h> #include <tchar.h>// 压缩文件 BOOL CompressFile(LPCTSTR lpSrcFileName, // 输入文件LPCTSTR lpDestFileName // 输出文件 );// 解压缩文件 BOOL UncompressFile(LPCTSTR lp…

在BrowserStack上进行自动化爬虫测试的终极指南

一、背景介绍 随着互联网的快速发展&#xff0c;数据变得越来越宝贵&#xff0c;爬虫技术已成为从网页中提取信息的重要工具。然而&#xff0c;在不同的环境中测试和运行爬虫脚本可能会带来挑战。尤其是在多浏览器、多平台的环境中确保爬虫的稳定性和兼容性是一个令人头疼的问…

GB/T28181和JT1078哪个更先进?

上篇blog我们探讨到GB/T28181规范和JT1078区别和各自应用场景&#xff0c;如果非要比较GB/T28181和JT1078哪个更先进&#xff0c;我们可以从二者更适合哪一类场景&#xff0c;包括规范的设计目标、功能特性、应用场景、技术发展趋势来做个探讨。 GB/T28181 GB/T28181&#xf…

电脑浏览器显示代理服务器拒绝连接的解决办法

问题&#xff1a; 打开电脑浏览器显示代理服务器拒绝连接 解决办法&#xff1a; 1、按住winq键&#xff0c;输入代理&#xff0c;出现更改代理设置 2、将下面的自动检测设置、使用设置脚本、使用代理服务器都设置为关闭&#xff0c;刷新网页即可

【Centos】绕开报错ModuleNotFoundError: No module named ‘dnf‘

问题原因&#xff1a; 安装python3.9后不能使用yum Traceback (most recent call last):File "/usr/bin/yum", line 57, in <module>from dnf.cli import main ModuleNotFoundError: No module named dnf绕开yum解决方法&#xff1a; 直接下载相关依赖包 htt…

性能优化:自动化处理系统设计

性能优化&#xff1a;自动化处理系统设计 前言需求分析系统设计1. 调度中心2. 任务执行器3. 错误处理机制4. 通知系统5. 报表生成器6. 日志记录器 技术实现结语 前言 在当今这个信息爆炸、技术日新月异的时代&#xff0c;企业面临着前所未有的挑战和机遇。随着业务量的不断增长…

ssm基于微信小程序的校园商铺系统论文源码调试讲解

第二章 系统实现的技术支持 2.1微信小程序框架 微信小程序的开发框架是微信所独有的一套框架&#xff0c;分为View视图层和App Service逻辑层两部分。框架提供了一种类似于Web中html语言的wxml语言&#xff0c;作为视图层的标签语言&#xff0c;用于构造页面的布局。另外提供了…

公式编辑支持SUBSTITUTE()函数

08/21 主要更新模块概览 条件展示 精准搜索 新增函数 有效时长 01 表单管理 1.1 【表单查询外链】-新增条件为空时不展示数据 说明&#xff1a; 之前表单查询外链&#xff0c;当查询外链的条件为空时&#xff0c;数据会全部展示。现在&#xff0c;我们新…

NetApp数据恢复—WAFL文件系统误删除的数据恢复案例

NetApp存储故障&#xff1a; 一台NetApp存储配置24块磁盘。管理员几个月之前删除一个文件夹&#xff0c;后期发现这个文件夹中的数据很重要&#xff0c;需要恢复。 根据NetApp文件系统WAFL的特性&#xff0c;新写入数据覆盖之前的数据的可能性不大&#xff0c;可以尝试恢复这个…

JAVA 二维码生成

1.pom依赖 <dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.3.3</version></dependency><dependency><groupId>com.google.zxing</groupId><artifactId>ja…

影响因子14.7!转录组和微生物组学纯分析!

研究背景 炎症性肠病(IBD)为累及回肠、直肠、结肠的一种特发性肠道炎症性疾病。临床表现腹泻、腹痛&#xff0c;甚至可有血便。本病包括溃疡性结肠炎(UC)和克罗恩病(CD)。粘膜水平上宿主-微生物相互作用的破坏是IBD病理生理的关键。本研究对收集的肠道活检组织进行了转录组学(…

可以收银的积分会员卡源码系统 带完整的安装代码包以及搭建部署教程

系统概述 随着消费市场的日益竞争激烈&#xff0c;商家需要不断探索新的营销方式来吸引和留住顾客。积分会员卡制度作为一种经典的营销策略&#xff0c;通过积分累积、兑换礼品、享受会员专属优惠等方式&#xff0c;有效提升了顾客的忠诚度和消费积极性。然而&#xff0c;传统…

010.Python爬虫系列_requests库详解(重点)

我 的 个 人 主 页:👉👉 失心疯的个人主页 👈👈 入 门 教 程 推 荐 :👉👉 Python零基础入门教程合集 👈👈 虚 拟 环 境 搭 建 :👉👉 Python项目虚拟环境(超详细讲解) 👈👈 PyQt5 系 列 教 程:👉👉 Python GUI(PyQt5)文章合集 👈👈 Oracle数

餐饮点餐API接口对接的一般步骤和注意事项

点餐API接口对接通常是指将餐饮服务的点餐系统与第三方平台&#xff08;如外卖平台、餐饮管理系统等&#xff09;通过API&#xff08;应用程序编程接口&#xff09;进行连接和集成的过程。这样的对接可以实现数据的实时同步和功能的互补&#xff0c;提高餐饮服务的效率和顾客的…