java多线程(三)重排序与Happens-Before
一、重排序
1.1 指令重排定义和含义
定义:重排序是指编译器和处理器为了提高程序执行效率,在不改变单线程程序执行结果的前提下,对指令执行顺序进行重新排列的一种优化手段。
重排序可以发生在编译器优化阶段,也可以发生在处理器执行指令阶段。
含义:
-
编译器优化的重排序:编译器在将高级语言代码转换成机器代码时,会进行各种优化,包括指令调度,即根据数据依赖关系分析哪些指令可以互换顺序而不影响最终执行结果。
-
指令级并行的重排序:现代处理器普遍采用指令级并行技术(ILP),允许多条无数据依赖性的指令同时执行,这实际上也是一种重排序。
-
内存系统的重排序:由于处理器使用了缓存和读写缓冲区,加载和存储操作可能看上去是乱序执行的,这也是一种内存系统的重排序。
1.2 指令重排序的意义
指令重排序是现代处理器为了提高程序执行速度而采用的一种优化技术。
其意义在于:
-
提高执行效率:处理器可以根据指令之间的依赖关系和资源情况,重新安排指令的执行顺序,从而充分利用多个执行单元并发执行指令,减少指令的等待时间,加快程序的执行速度。
-
优化资源利用:指令重排序可以优化处理器内部资源的利用,如运算单元、缓存和寄存器等。通过重新排序指令,处理器可以减少资源的空闲时间,提高资源的利用率。
-
增加并行性:指令重排序可以增加指令级的并行性,使处理器能够同时执行多条指令,提高系统的整体性能和响应速度。
1.3 示例说明
在Java中,指令重排序通常是由JVM(Java虚拟机)或底层硬件自动完成的,不需要程序员直接干预。
但是,指令重排序可能导致多线程程序中的数据不一致性问题。
以下是一个简单的Java代码示例,说明指令重排序可能引发的问题:
public class ReorderExample {private int a = 0;private boolean flag = false;public void method1() {a = 1; // 语句1flag = true; // 语句2}public void method2() {if (flag) { // 语句3int temp = a + 5; // 语句4,这里假设我们要使用a的值System.out.println(temp);}}
}
假设method1
和method2
分别在两个不同的线程中执行,我们期望在flag
为true
时,a
的值已经为1
,因此temp
的值为6
。
然而,由于指令重排序,语句1和语句2的执行顺序可能会互换,导致在method2
中flag
为true
时,a
的值可能还是0
,从而输出错误的结果。
为了避免这种问题,Java提供了volatile
关键字或synchronized
同步块来确保内存可见性和有序性。
二、Happens-Before
2.1 Happens-Before的定义和含义
定义:Happens-Before是Java内存模型(JMM)中的一个核心概念,用于定义两个操作之间的内存可见性和执行顺序关系。
如果一个操作A happens-before 另一个操作B,那么A的执行结果将对B可见,且A的执行顺序排在B之前。
含义:
-
内存可见性:保证了一个线程的操作结果对另一个线程可见,这是多线程编程中保证数据一致性的关键。
-
执行顺序:虽然Happens-Before关系不严格要求物理执行顺序,但它为程序员提供了一个可依赖的逻辑顺序,使得并发程序的编写和理解变得更为简单。
2.2 Happens-Before 与 JMM
Happens-Before是Java内存模型(JMM)中的一个重要概念,用于定义两个操作之间的内存可见性顺序。
如果一个操作A happens-before另一个操作B,那么操作A的结果对操作B是可见的,即操作B在执行时能够看到操作A的结果。
JMM通过Happens-Before规则来确保多线程程序的内存可见性和有序性,避免数据不一致的问题。这些规则包括:
-
程序顺序规则:在同一个线程内,按照程序代码的顺序,书写在前面的操作happens-before于书写在后面的操作。
-
锁规则:对一个锁的解锁操作happens-before于随后对这个锁的加锁操作。
-
volatile变量规则:对一个volatile变量的写操作happens-before于随后对这个volatile变量的读操作。
-
线程启动规则:Thread对象的start()方法调用happens-before于此线程的每一个操作。
-
线程终止规则:线程中的所有操作都happens-before于其他线程检测到该线程已经终止(例如,通过Thread.join()方法等待线程结束)。
2.3 示例说明
以下是一个使用volatile
变量来演示Happens-Before规则的Java代码示例:
public class VolatileExample {private volatile boolean flag = false;private int number = 0;public void writer() {number = 42; // 语句1flag = true; // 语句2}public void reader() {if (flag) { // 语句3System.out.println(number); // 语句4,这里假设我们要读取number的值}}
}
在这个例子中,由于flag
变量被声明为volatile
,根据Happens-Before的volatile变量规则,对flag
的写操作(语句2)happens-before对flag
的读操作(语句3)。
因此,当读操作看到flag
为true
时,它一定能看到之前对number
的写操作(语句1)的结果,即number
的值为42
。
这确保了多线程程序中的内存可见性,避免了由于指令重排序导致的数据不一致问题。
三、最后
-
多线程编程:在多线程环境下,重排序可能导致数据竞争和不一致现象,而Happens-Before原则为程序员提供了一套规则,确保跨线程的内存可见性和执行顺序的一致性。
-
性能优化:编译器和处理器通过重排序优化指令执行顺序,提高CPU利用率和程序执行效率。然而,这种优化必须在不改变程序执行结果的前提下进行。
-
保证数据一致性:在多线程程序中,数据一致性的保证是并发编程的核心问题之一。Happens-Before原则通过定义操作之间的内存可见性和执行顺序关系,为程序员提供了编写正确同步多线程程序的依据。
-
提高程序执行效率:重排序作为一种优化手段,能够在不改变单线程程序执行结果的前提下,显著提高程序执行效率。然而,这种优化必须谨慎进行,以避免引入多线程问题。
这里先备注一下,没学懂。用不用volatile感觉没什么区别。
相关文章:
java多线程(三)重排序与Happens-Before
一、重排序 1.1 指令重排定义和含义 定义:重排序是指编译器和处理器为了提高程序执行效率,在不改变单线程程序执行结果的前提下,对指令执行顺序进行重新排列的一种优化手段。 重排序可以发生在编译器优化阶段,也可以发生在处理…...
RUST知识框架与学习框架
RUST知识框架与学习框架 Rust是一门系统级编程语言,以其内存安全、高性能和并发性而著称,特别适用于开发低级系统、网络服务和并发应用,具有广泛应用前景。 一、Rust知识框架 基础语法与核心概念 变量与类型:包括基本数据类型、…...
git cherry-pick命令使用分享
在日常开发中,有时候会遇到一种情况,线上出了问题,但是现在的预生产环境(Pre-production Environment)或准生产环境(Stage Environment)有还未通过验收的内容,那么想进行修复可以选择…...

关闭Chrome快捷键
chrome是没办法改变快捷键以及屏蔽快捷键的,需要安装插件:shortkey 保证插件是开启的 不用做其他设置所有快捷键已被关闭...

常见DDoS攻击之零日漏洞Zero-day Attacks
目录 一、什么是零日漏洞Zero-day Attacks 二、零日漏洞是如何转化为零日攻击的 三、常见的零日攻击类型 四、为什么零日攻击很危险 五、著名的零日攻击事件 六、如何降低零日攻击的风险 七、DDoS攻击防御解决方案(定制化) 7.1 产品优势 7.2 产品…...
【字符串】Z函数 - 模板
z [ i ] z[i] z[i] 表示字符串 s s s 和 s [ i , n − 1 ] s[i,\ n - 1] s[i, n−1] 的最长前缀的长度,特别的, z [ 0 ] 0 z[0]0 z[0]0 // *********Z函数************** // - 时间复杂度 O(n) vector<int> z_function(string s) {int n (int…...

MySQL范围分区分区表
什么是范围分区分区表? 范围分区是一种根据某个列的范围值来分割表数据的分区方式。在范围分区中,每个分区都有自己的范围条件,当插入数据时,MySQL会根据指定的范围条件将数据分配到相应的分区中。这种分区方式可以使得表的数据按…...

网络UDP报文详细解析
目录 一、简介二、详细介绍三、其他相关链接1、TCP报文段的详细图总结2、TCP三次握手和四次挥手详解3、socket通信原理及相关函数详细总结4、网络包IP首部详细解析 一、简介 本文主要介绍UDP报文格式。 二、详细介绍 UDP是一种无连接、不可靠的用户数据报协议,其…...

望繁信科技入选2024年第3批上海市高新技术成果转化项目名单
近日,上海望繁信科技有限公司(以下简称“望繁信科技”)凭借其自主研发的“数字北极星流程挖掘分析软件”项目,成功入选2024年第3批上海市高新技术成果转化项目名单。这一殊荣根据《上海市高新技术成果转化项目认定办法》ÿ…...
深入探讨MySQL的锁机制:全局锁、表级锁和行级锁
深入探讨MySQL的锁机制:全局锁、表级锁和行级锁 在数据库管理中,锁机制是确保数据一致性和并发控制的重要手段。MySQL提供了多种锁策略,包括全局锁、表级锁和行级锁。本文将详细探讨这些锁机制的概念、使用场景及其示例代码,帮助…...

iLogtail 开源两周年:感恩遇见,畅想未来
早在上世纪 60 年代,早期的计算机(例如 ENIAC 和 IBM 的大型机)在操作过程中会输出一些基本的状态信息和错误报告,这些记录通常通过打印机输出到纸带或纸卡上,用于跟踪操作流程和调试,最早期的日志系统借此…...

写给大数据开发:在Databricks中自定义函数
你是否曾经在处理海量数据时感到力不从心?是否在重复编写相似代码时感到厌烦?如果是,那么Databricks中的自定义函数可能就是你一直在寻找的救星。在接下来的5分钟里,让我们一起探索如何利用这个强大的工具来revolutionize你的大数据开发工作流程。 目录 为什么要在Databrick…...

VMware vSphere Client无法访问和连接ESXi虚拟主机解决思路
文章目录 前言1. 问题现象2. 问题原因3. 解决方法4. 参考文章 前言 注意 : 可以先看看参考文章那里,在回过来看 1 、 2 、3 1. 问题现象 版本:VMware vCenter Server 5.5.0 build-2442329 问题描述:用VMware vSphere Client 登录ESXI主机出…...

实现Kruskal算法连通游戏地图地牢
前置知识 c分享|并查集从入门到出门 - 力扣(LeetCode) 彻底搞懂克鲁斯卡尔(Kruskal)算法(附C代码实现) - QuanHa - 博客园 (cnblogs.com) 白色点矩形是地牢,其中白线是按照krsukal…...

turtle画图知识
Turtle库是Python编程语言中的一个库,用于创建各种类型的图形,包括简单圆形、线条、路径和图片。它支持多种图形类型,并且可以绘制出各种复杂的形状。 以下是一些基本的使用方法: 1. 创建一个新的Turtle对象: pytho…...
Elasticsearch简述
Elasticsearch简述 Elasticsearch产品介绍 Elasticsearch是一个基于Apache Lucene的开源的分布式搜索和分析引擎,设计用于云计算中,能够快速处理大量数据。它能够近实时地进行复杂的查询,并且可以用于全文检索、结构化搜索以及分析。Elasticsearch具有以下特性: 分布式搜索…...

SQL— DDL语句学习【后端 9】
SQL— DDL语句学习 在数据管理的广阔领域中,SQL(Structured Query Language)作为操作关系型数据库的编程语言,扮演着举足轻重的角色。它不仅定义了操作所有关系型数据库的统一标准,还为我们提供了强大的工具来管理、查…...

线程池介绍
1.线程池简介 import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class CallableDemo {public sta…...

如何备份电脑所有数据?有哪些方法值得参考借鉴?
备份电脑所有数据是防护数据丢失和泄密的重要一项措施,备份数据也有不同的方式和工具,正确的工具能帮你省时省力,下面盘点了几个方法,来看哪一种最适合你。 一、使用专业备份软件 第三方服务器文件自动备份软件:如安企…...

初识--树(1)
下面就是这篇博客要讲的内容 树 二叉树堆 树概念及结构二叉树的概念及结构二叉树的实现堆的概念及运用 这篇博客主要以二叉树为主要内容。 1、树的概念及结构 1.1树的概念: 树是一种非线性的数据结构,它是由n(n>0)个有限…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
Admin.Net中的消息通信SignalR解释
定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...
spring:实例工厂方法获取bean
spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂ÿ…...

【2025年】解决Burpsuite抓不到https包的问题
环境:windows11 burpsuite:2025.5 在抓取https网站时,burpsuite抓取不到https数据包,只显示: 解决该问题只需如下三个步骤: 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...
HTML前端开发:JavaScript 常用事件详解
作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...
React---day11
14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store: 我们在使用异步的时候理应是要使用中间件的,但是configureStore 已经自动集成了 redux-thunk,注意action里面要返回函数 import { configureS…...
虚拟电厂发展三大趋势:市场化、技术主导、车网互联
市场化:从政策驱动到多元盈利 政策全面赋能 2025年4月,国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》,首次明确虚拟电厂为“独立市场主体”,提出硬性目标:2027年全国调节能力≥2000万千瓦࿰…...

STM32HAL库USART源代码解析及应用
STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...