1. 指令重排基础概念
    • 在现代处理器和编译器为了提高程序执行效率,会对指令进行优化,其中一种优化方式就是指令重排序。在单线程环境下,指令重排序不会影响最终执行结果,因为处理器和编译器会保证重排序后的执行结果与按照代码顺序执行的结果一致。但在多线程环境下,指令重排序可能会导致程序出现意外的行为。
    • 例如,处理器可能会将一些不依赖于其他指令结果的指令提前执行,以充分利用处理器资源。编译器也可能对代码进行优化,改变指令的顺序。
  2. volatile 禁止指令重排原理
    • volatile 关键字具有禁止指令重排序的语义。Java内存模型(JMM)规定,对 volatile 变量的写操作,先行发生于后续对这个 volatile 变量的读操作。这意味着,在 volatile 变量的写操作之前的所有操作,都必须在 volatile 变量的写操作之前完成;而 volatile 变量的读操作,必须在其之后的所有操作之前完成。这种规则确保了 volatile 变量相关的操作顺序与代码顺序一致,从而避免了指令重排序带来的问题。
  3. 代码示例及执行顺序分析
    • 示例1:单例模式中的指令重排问题与 volatile 作用
public class Singleton {// 未使用volatile时可能会出现指令重排问题private static Singleton instance; private Singleton() {}public static Singleton getInstance() {if (instance == null) { // 第一次检查synchronized (Singleton.class) {if (instance == null) { // 第二次检查// 这里可能发生指令重排instance = new Singleton(); }}}return instance;}
}

在上述代码中,instance = new Singleton(); 这行代码实际上包含了三个步骤:

    1. 分配内存空间给 Singleton 对象。
    1. 初始化 Singleton 对象。
    1. instance 指向分配的内存空间。

在没有 volatile 修饰的情况下,编译器和处理器可能会对这三个步骤进行重排序,比如先执行步骤1和3,然后再执行步骤2。假设线程A执行 getInstance() 方法,在步骤1和3执行后,但步骤2还未执行时,线程B进入 getInstance() 方法,此时 instance 已经非空(因为已经指向了分配的内存空间),线程B会直接返回 instance,但此时 instance 还未初始化完成,这就会导致程序出错。

使用 volatile 修饰 instance 后:

public class Singleton {// 使用volatile防止指令重排private static volatile Singleton instance; private Singleton() {}public static Singleton getInstance() {if (instance == null) { // 第一次检查synchronized (Singleton.class) {if (instance == null) { // 第二次检查instance = new Singleton(); }}}return instance;}
}

volatile 关键字保证了这三个步骤不会被重排序,一定是按照1 -> 2 -> 3的顺序执行,从而确保了 instance 在被其他线程获取时已经完全初始化。

  • 示例2:简单变量操作中的指令重排与 volatile
public class VolatileReorderingExample {private static int a = 0;private static volatile boolean flag = false;public static void main(String[] args) {Thread thread1 = new Thread(() -> {a = 1; // 语句1flag = true; // 语句2});Thread thread2 = new Thread(() -> {while (!flag) {// 等待flag变为true}System.out.println(a); // 语句3});thread1.start();thread2.start();}
}

在上述代码中,如果 flag 没有被声明为 volatile,由于指令重排,语句1和语句2的执行顺序可能会被改变,即先执行 flag = true; 然后再执行 a = 1;。这样当线程2执行到 System.out.println(a); 时,a 可能还没有被赋值为1,输出结果可能为0。

而当 flag 被声明为 volatile 后,JMM保证了语句1一定在语句2之前执行,并且语句1的结果对线程2可见。所以当线程2执行 System.out.println(a); 时,a 一定已经被赋值为1,输出结果为1。

总结来说,volatile 通过JMM的规则,限制了编译器和处理器对 volatile 变量相关指令的重排序,确保了多线程环境下程序的执行顺序符合预期,避免了因指令重排导致的错误。

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【硬件开发】滤波电容的选择:原理、计算与多电压值应用实践

滤波电容的选择:原理、计算与多电压值应用实践 1. 引言 在现代电子系统中,稳定的电源供应是保证电路可靠运行的基础。然而,电源线上往往不可避免地存在各种噪声和纹波,这些干扰可能源自电源本身(如整流后的脉动直流&…

【seismic unix数据生成-unif2】

Seismic Unix简介 Seismic Unix(SU)是由科罗拉多矿业学院(Colorado School of Mines)开发的开源地震数据处理软件包,专为地震勘探数据分析和研究设计。它提供了一系列命令行工具,支持从数据加载、处理到可…

【逆向思考 并集查找】P2391 白雪皑皑|省选-

本文涉及知识点 C并集查找 P2391 白雪皑皑 题目背景 “柴门闻犬吠,风雪夜归人”,冬天,不期而至。千里冰封,万里雪飘。空中刮起了鸭毛大雪。雪花纷纷,降落人间。 美能量星球(pty 在 spore 上的一个殖民地…

一文讲清楚React中setState的使用方法和机制

文章目录 一文讲清楚React中setState的使用方法和机制1. setState是什么2. setState方法详解2.1 setState参数详解2.2 setState同步异步问题2.2.1 setState异步更新2.2.2 setState同步更新 一文讲清楚React中setState的使用方法和机制 1. setState是什么 React中,…

01_软件卓越之道:功能性与需求满足

引言 在软件的世界里,功能性是产品与用户之间的第一桥梁。一个软件即使拥有华丽的界面和极致的性能,如果不能解决用户的核心需求,也终将被市场淘汰。本文将深入探讨如何确保软件的功能性与用户需求完美契合。 1. 需求理解:从模糊…

StarRocks × Tableau 连接器完整使用指南 | 高效数据分析从连接开始

一、导语:为什么选择 StarRocks Tableau 连接器? 在当今数据驱动的商业环境中,企业不仅需要一个能够处理海量数据的高性能分析数据库,还需要一个直观、强大的可视化工具来解读数据背后的故事。StarRocks 作为新一代极速全场景 MP…

基于 SpringBoot+VueJS 助农生鲜销售系统设计与实现7000字论文实现

摘要本论文设计并实现了一个基于 SpringBoot 和 VueJS 的助农生鲜销售系统。系统采用前后端分离架构,前端使用 VueJS 框架实现用户界面,后端使用 SpringBoot 框架构建服务,通过 MyBatis 实现数据持久化。系统实现了农产品展示、在线购物、订单…

Pytest 测试发现机制详解:自动识别测试函数与模块

概述 在编写自动化测试时,如何让 Pytest 自动找到你的测试代码 是一个非常基础但重要的问题。Pytest 通过其强大的 测试发现(Test Discovery)机制,能够自动扫描项目目录、识别测试模块和测试函数,从而大大简化了测试流程。 本文将为你详细讲解 Pytest 的测试发现机制,包…

MySQL 时间日期函数

时间日期类型 MySQL中主要支持以下几种时间日期类型: DATE - 日期类型 格式:YYYY-MM-DD范围:1000-01-01 到 9999-12-31示例:2023-05-20 TIME - 时间类型 格式:HH:MM:SS范围:-838:59:59 到 838:59:59示例&…

408第三季part2 - 计算机网络 - 物理层

理解 这里有8个波形,每个波形代表一个马原,一个马原代表多个比特,这里3个比特 求波特率就直接2W 求比特率就要乘log2V 这块记两公式就行,一个下面一个上面 题目 4个相位加4种幅度就是有16种波形 这里无噪声就是奈奎斯特定理 这…

iOS 集成RN Installing glog (0.3.5)报错的解决方案

在集成执行RN bundle exec pod install 命令到Installing glog (0.3.5)时报错,报错信息如下: Installing glog (0.3.5) [!] /bin/bash -c set -e #!/bin/bash # Copyright (c) Facebook, Inc. and its affiliates. # # This source code is licensed under the MIT license …

【进阶篇-消息队列】——MQTT协议如何支持海量的在线IoT设备

目录 一、什么是IoT二、MQTT 和其他消息队列的传输协议有什么不同三、如何选择 MQTT 产品四、MQTT 集群如何支持海量在线的 IoT 设备五、总结本文来源:极客时间vip课程笔记 一、什么是IoT IoT,也就是物联网,物联网这个词儿,它的含义还不那么直观,但你看它的英文:IoT,也就…

Chat Model API

聊天模型API为开发人员提供了将人工智能聊天完成功能集成到应用程序中的能力。它利用预训练的语言模型,如GPT(生成预训练转换器),以自然语言对用户输入生成类似人类的响应。 API通常通过向人工智能模型发送提示或部分对话来工作&…

【黑群晖】自组硬件/旧电脑nas改造(三)——使用Jellyfin创建家庭影音库

一、打开套件中心安装Jellyfin套件 如果找不到Jellyfin套件,需要手动添加三方套件源: 《群晖NAS必学技能:一键解锁三方套件源,PT下载影音播放全搞定!》 二、配置Jellyfin 访问http://群晖IP:8096 进入Jellyfin初始化界…

泰山派编译debian报错 lb config: unrecognized option ‘--debootstrap-options‘

简介 最近在编译泰山派 编译buildroot系统正常,但是编译debian时总是报错说lb 找不到一些参数,如下图所示,应该当前的版本较低 不支持这些参数,我试了很多方法 升级次版本 但是提示的是最新的,最后经过一番搜索 在官方…

跨境证券交易系统合规升级白皮书:全链路微秒风控+开源替代,护航7月程序化交易新规落地

1 行业变革:四重驱动力重塑证券交易系统 当前全球证券行业正处于深刻变革期,跨境金融活动面临前所未有的机遇与挑战。今日央行开展的1310亿元7天期逆回购操作,以及国家外汇管理局向合格境内机构投资者(QDII)新增发放30.8亿美元投资额度等政策…

Node.js核心API(fs篇)

前言:在Node.js生态系统中,文件系统操作是后端开发不可或缺的一部分。fs模块作为Node.js核心API的重要组成部分,提供了与文件系统交互的能力,涵盖了从基础的文件读写到复杂的目录操作等功能。现代JavaScript开发中,处理…

HarmonyOS学习2---Stage模型

1、工程目录结构 1.1、入口 UIAbility 1.2、入口page 1.3、配置文件 1、配置文件 1)应用级配置文件 --- app.json5 2)模块级配置文件 --- module.json5 3、oh-package.json5 4、资源文件 1)element目录 2)media目录 3&#xff09…

【软件工程】软件复刻项目的完整流程指南

软件复刻项目的完整流程指南 第一章、概述 一、前期准备:明确目标与合规性 1. 法律风险评估 版权排查:确认目标软件的 UI 设计、代码、商标是否受保护(如界面元素、核心算法是否申请专利)。规避侵权:避免直接复制 …

浅谈Python 中的当前工作目录与脚本目录

Python 中的 os.path.exists() 和 __file__ 使用陷阱:工作目录 ≠ 脚本目录 在使用 os.path.exists() 或 open() 等函数操作文件路径时,笔者常常忽略一个关键概念:当前运行目录(Current Working Directory, CWD)并不等…