当前位置: 首页 > news >正文

java多线程(三)重排序与Happens-Before

一、重排序

1.1 指令重排定义和含义

定义:重排序是指编译器和处理器为了提高程序执行效率,在不改变单线程程序执行结果的前提下,对指令执行顺序进行重新排列的一种优化手段。

重排序可以发生在编译器优化阶段,也可以发生在处理器执行指令阶段。

含义

  • 编译器优化的重排序:编译器在将高级语言代码转换成机器代码时,会进行各种优化,包括指令调度,即根据数据依赖关系分析哪些指令可以互换顺序而不影响最终执行结果。

  • 指令级并行的重排序:现代处理器普遍采用指令级并行技术(ILP),允许多条无数据依赖性的指令同时执行,这实际上也是一种重排序。

  • 内存系统的重排序:由于处理器使用了缓存和读写缓冲区,加载和存储操作可能看上去是乱序执行的,这也是一种内存系统的重排序。

1.2 指令重排序的意义

指令重排序是现代处理器为了提高程序执行速度而采用的一种优化技术。

其意义在于:

  1. 提高执行效率:处理器可以根据指令之间的依赖关系和资源情况,重新安排指令的执行顺序,从而充分利用多个执行单元并发执行指令,减少指令的等待时间,加快程序的执行速度。

  2. 优化资源利用:指令重排序可以优化处理器内部资源的利用,如运算单元、缓存和寄存器等。通过重新排序指令,处理器可以减少资源的空闲时间,提高资源的利用率。

  3. 增加并行性:指令重排序可以增加指令级的并行性,使处理器能够同时执行多条指令,提高系统的整体性能和响应速度。

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);}}
}

假设method1method2分别在两个不同的线程中执行,我们期望在flagtrue时,a的值已经为1,因此temp的值为6

然而,由于指令重排序,语句1和语句2的执行顺序可能会互换,导致在method2flagtrue时,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规则来确保多线程程序的内存可见性和有序性,避免数据不一致的问题。这些规则包括:

  1. 程序顺序规则:在同一个线程内,按照程序代码的顺序,书写在前面的操作happens-before于书写在后面的操作。

  2. 锁规则:对一个锁的解锁操作happens-before于随后对这个锁的加锁操作。

  3. volatile变量规则:对一个volatile变量的写操作happens-before于随后对这个volatile变量的读操作。

  4. 线程启动规则:Thread对象的start()方法调用happens-before于此线程的每一个操作。

  5. 线程终止规则:线程中的所有操作都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)。

因此,当读操作看到flagtrue时,它一定能看到之前对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] 的最长前缀的长度&#xff0c;特别的&#xff0c; z [ 0 ] 0 z[0]0 z[0]0 // *********Z函数************** // - 时间复杂度 O(n) vector<int> z_function(string s) {int n (int…...

MySQL范围分区分区表

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

网络UDP报文详细解析

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

望繁信科技入选2024年第3批上海市高新技术成果转化项目名单

近日&#xff0c;上海望繁信科技有限公司&#xff08;以下简称“望繁信科技”&#xff09;凭借其自主研发的“数字北极星流程挖掘分析软件”项目&#xff0c;成功入选2024年第3批上海市高新技术成果转化项目名单。这一殊荣根据《上海市高新技术成果转化项目认定办法》&#xff…...

深入探讨MySQL的锁机制:全局锁、表级锁和行级锁

深入探讨MySQL的锁机制&#xff1a;全局锁、表级锁和行级锁 在数据库管理中&#xff0c;锁机制是确保数据一致性和并发控制的重要手段。MySQL提供了多种锁策略&#xff0c;包括全局锁、表级锁和行级锁。本文将详细探讨这些锁机制的概念、使用场景及其示例代码&#xff0c;帮助…...

iLogtail 开源两周年:感恩遇见,畅想未来

早在上世纪 60 年代&#xff0c;早期的计算机&#xff08;例如 ENIAC 和 IBM 的大型机&#xff09;在操作过程中会输出一些基本的状态信息和错误报告&#xff0c;这些记录通常通过打印机输出到纸带或纸卡上&#xff0c;用于跟踪操作流程和调试&#xff0c;最早期的日志系统借此…...

写给大数据开发:在Databricks中自定义函数

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

VMware vSphere Client无法访问和连接ESXi虚拟主机解决思路

文章目录 前言1. 问题现象2. 问题原因3. 解决方法4. 参考文章 前言 注意 : 可以先看看参考文章那里&#xff0c;在回过来看 1 、 2 、3 1. 问题现象 版本&#xff1a;VMware vCenter Server 5.5.0 build-2442329 问题描述&#xff1a;用VMware vSphere Client 登录ESXI主机出…...

实现Kruskal算法连通游戏地图地牢

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

turtle画图知识

Turtle库是Python编程语言中的一个库&#xff0c;用于创建各种类型的图形&#xff0c;包括简单圆形、线条、路径和图片。它支持多种图形类型&#xff0c;并且可以绘制出各种复杂的形状。 以下是一些基本的使用方法&#xff1a; 1. 创建一个新的Turtle对象&#xff1a; pytho…...

Elasticsearch简述

Elasticsearch简述 Elasticsearch产品介绍 Elasticsearch是一个基于Apache Lucene的开源的分布式搜索和分析引擎,设计用于云计算中,能够快速处理大量数据。它能够近实时地进行复杂的查询,并且可以用于全文检索、结构化搜索以及分析。Elasticsearch具有以下特性: 分布式搜索…...

SQL— DDL语句学习【后端 9】

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

线程池介绍

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…...

如何备份电脑所有数据?有哪些方法值得参考借鉴?

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

初识--树(1)

下面就是这篇博客要讲的内容 树 二叉树堆 树概念及结构二叉树的概念及结构二叉树的实现堆的概念及运用 这篇博客主要以二叉树为主要内容。 1、树的概念及结构 1.1树的概念&#xff1a; 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限…...

反向工程与模型迁移:打造未来商品详情API的可持续创新体系

在电商行业蓬勃发展的当下&#xff0c;商品详情API作为连接电商平台与开发者、商家及用户的关键纽带&#xff0c;其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息&#xff08;如名称、价格、库存等&#xff09;的获取与展示&#xff0c;已难以满足市场对个性化、智能…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

React---day11

14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store&#xff1a; 我们在使用异步的时候理应是要使用中间件的&#xff0c;但是configureStore 已经自动集成了 redux-thunk&#xff0c;注意action里面要返回函数 import { configureS…...

DingDing机器人群消息推送

文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人&#xff0c;点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置&#xff0c;详见说明文档 成功后&#xff0c;记录Webhook 2 API文档说明 点击设置说明 查看自…...

打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用

一、方案背景​ 在现代生产与生活场景中&#xff0c;如工厂高危作业区、医院手术室、公共场景等&#xff0c;人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式&#xff0c;存在效率低、覆盖面不足、判断主观性强等问题&#xff0c;难以满足对人员打手机行为精…...

云原生安全实战:API网关Envoy的鉴权与限流详解

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关 作为微服务架构的统一入口&#xff0c;负责路由转发、安全控制、流量管理等核心功能。 2. Envoy 由Lyft开源的高性能云原生…...

6.9本日总结

一、英语 复习默写list11list18&#xff0c;订正07年第3篇阅读 二、数学 学习线代第一讲&#xff0c;写15讲课后题 三、408 学习计组第二章&#xff0c;写计组习题 四、总结 明天结束线代第一章和计组第二章 五、明日计划 英语&#xff1a;复习l默写sit12list17&#…...

react-pdf(pdfjs-dist)如何兼容老浏览器(chrome 49)

之前都是使用react-pdf来渲染pdf文件&#xff0c;这次有个需求是要兼容xp环境&#xff0c;xp上chrome最高支持到49&#xff0c;虽然说iframe或者embed都可以实现预览pdf&#xff0c;但为了后续的定制化需求&#xff0c;还是需要使用js库来渲染。 chrome 49测试环境 能用的测试…...

mcts蒙特卡洛模拟树思想

您这个观察非常敏锐&#xff0c;而且在很大程度上是正确的&#xff01;您已经洞察到了MCTS算法在不同阶段的两种不同行为模式。我们来把这个关系理得更清楚一些&#xff0c;您的理解其实离真相只有一步之遥。 您说的“select是在二次选择的时候起作用”&#xff0c;这个观察非…...

break 语句和 continue 语句

break语句和continue语句都具有跳转作用&#xff0c;可以让代码不按既有的顺序执行 break break语句用于跳出代码块或循环 1 2 3 4 5 6 for (var i 0; i < 5; i) { if (i 3){ break; } console.log(i); } continue continue语句用于立即终…...