volatile之四类内存屏障指令 内存屏障 面试重点 底层源码

目录

volatile 两大特性

可见性

有序性

总结

什么是内存屏障

四个 CPU 指令

四大屏障

重排

重排的类型

为什么会有重排?

线程中的重排和可见性问题

如何防止重排引发的问题?

总结

happens-before 和 volatile 变量规则

内存屏障指令 写操作

volatile 写操作前有一个 storestore 屏障

volatile 写操作后有一个 storeload 屏障

内存屏障指令 读操作

volatile 读操作后有一个loadload屏障和一个 loadstore 屏障


volatile 两大特性

可见性

在多线程环境下,每个线程可能会维护自己的本地缓存(例如 CPU 缓存或者线程私有的缓存),因此一个线程对 volatile 变量的修改对其他线程是立即可见的。

有序性

在多线程环境下,每个线程可能会维护自己的本地缓存(例如 CPU 缓存或者线程私有的缓存),因此一个线程对 volatile 变量的修改对其他线程是立即可见的。

  • 当一个线程修改了 volatile 变量的值,其他线程可以看到这个修改,因为 volatile 变量的更新会直接刷新到主内存中(而不是线程本地的缓存)。
  • 缓存一致性:Java 内存模型 (JMM) 保证了写入 volatile 变量会直接更新主内存,并且读取时会从主内存中获取数据,从而确保了其他线程能够及时看到变量的最新值。

总结

当写一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量值立即刷新回主内存中。

当读一个volatile变量时,JMM会把该线程对应的本地内存设置为无效,直接从主内存中读取共享变量

所以volatile的写内存语义是直接刷新到主内存中,读的内存语义是直接从主内存中读取。

什么是内存屏障

Java 操作内存的后门

四个 CPU 指令

加载 和 存储

loadload()

storestore()

loadstore()

storeload()


四大屏障

屏障类型是 loadload

屏障类型是 storestore

屏障类型是 loadstore

屏障类型是 loadstore

重排

在多线程编程中,重排(Reordering)是指编译器、CPU 或 JVM 在执行程序时,出于性能优化的目的,改变了代码执行的顺序,但不改变程序的最终行为(如果没有数据依赖关系的话)。这通常是在指令级别或者内存访问顺序上发生的。

重排的类型

  1. 指令重排(Instruction Reordering):
    • 编译器可能会改变语句的执行顺序,但保证语义不变。
    • 例如,在循环中,如果没有数据依赖关系,编译器可以将某些计算移到循环外部执行。
  1. 内存重排(Memory Reordering):
    • CPU 或缓存系统可能会改变内存操作的顺序,从而影响多个线程对共享变量的访问顺序。
    • 这可能会导致不同步的线程看到的数据状态不一致,尤其是在没有适当同步的情况下。

为什么会有重排?

重排的主要目的是提高程序的执行效率。例如,编译器或处理器可能将某些不依赖的操作交换顺序,从而减少等待时间或提高并行性。然而,如果不小心,这也可能导致并发程序中的可见性问题,即线程看到的数据不一致,或者多线程的执行顺序与我们期望的不一致。

线程中的重排和可见性问题

在多线程程序中,重排的危险通常与线程之间的内存可见性执行顺序有关。举个简单的例子:

boolean flag = false;

Thread t1 = new Thread(() -> {
    flag = true;   // A
});

Thread t2 = new Thread(() -> {
    if (flag) {    // B
        System.out.println("Flag is true");
    }
});

t1.start();
t2.start();

在这个例子中,如果没有适当的同步机制,t2 可能会比 t1 先执行,即 t2 可能在 flag 变量还没有被 t1 更新时就执行了。如果处理器或编译器对内存访问进行了重排,t2 可能看到的是 flagfalse,即使 t1 已经把它设置为 true。这是因为在不同线程间的内存访问可能没有同步,导致重排影响了线程间的可见性。

如何防止重排引发的问题?

  1. 使用 volatile 关键字
    • volatile 关键字能够防止对变量的重排序,也确保每个线程都能看到变量的最新值。
    • 它告诉 JVM 和 CPU,所有的线程都应该直接从主内存中读取该变量的值,而不是从缓存中读取。
java


复制编辑
private volatile boolean flag = false;
  1. 使用同步(synchronizedLock
    • synchronized 能够保证同一时刻只有一个线程执行某个代码块,并且它还可以保证内存的可见性,即写入的值对其他线程可见。
    • 通过使用 synchronized 或显式的 Lock,可以避免并发环境中的重排序和可见性问题。
  1. 使用 final 关键字
    • 对于一些常量(即初始化后不再修改的变量),使用 final 可以避免变量被重排,确保多线程读取时不会遇到问题。

总结

重排是为了优化性能而发生的一种行为,但在多线程环境中,若没有正确的同步机制,重排可能导致程序行为不一致,尤其是在共享数据的访问上。为了防止这类问题,我们通常会使用 volatilesynchronized 或其他同步机制来保证多线程程序的正确性。

如果你有更多具体的多线程问题,或者有其他相关概念不太明白,随时可以继续问我!

happens-before 和 volatile 变量规则

只要是第一个操作是 voliatile 读 都不能重排

只要是第二个操作是 voliatile 写 都不能重排

voliatile 读写 后 voliatile 读写 都不难重排

内存屏障指令 写操作

volatile 写操作前有一个 storestore 屏障

volatile 写操作后有一个 storeload 屏障

内存屏障指令 读操作

volatile 读操作后有一个loadload屏障和一个 loadstore 屏障

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

力扣算法题——11.盛最多水的容器

目录 💕1.题目 💕2.解析思路 本题思路总览 借助双指针探索规律 从规律到代码实现的转化 双指针的具体实现 代码整体流程 💕3.代码实现 💕4.完结 二十七步也能走完逆流河吗 💕1.题目 💕2.解析思路…

RK3568 adb使用

文章目录 一、adb介绍**ADB 主要功能****常用 ADB 命令****如何使用 ADB****总结** 二、Linux下载adb**方法 1:使用包管理器(适用于 Ubuntu/Debian 系统)****方法 2:通过 Snap 安装(适用于支持 Snap 的系统&#xff09…

【ES实战】治理项之索引模板相关治理

索引模板治理 文章目录 索引模板治理问题现象分析思路操作步骤问题程序化方案索引与索引模板增加分片数校验管理 彩蛋如何查询Flink on Yarn 模式下的Task Manager日志相关配置查询已停止的Flink任务查询未停止的Flink任务 问题现象 在集群索引新建时,索引的分片比…

网络工程师 (2)计算机体系结构

一、冯诺依曼体系结构 (一)简介 冯诺依曼结构也称普林斯顿结构,是一种将程序指令存储器和数据存储器合并在一起的存储器结构。程序指令存储地址和数据存储地址指向同一个存储器的不同物理位置,因此程序指令和数据的宽度相同。数学…

Android Studio:视图绑定的岁月变迁(2/100)

一、博文导读 本文是基于Android Studio真实项目,通过解析源码了解真实应用场景,写文的视角和读者是同步的,想到看到写到,没有上帝视角。 前期回顾,本文是第二期。 private Unbinder mUnbinder; 只是声明了一个 接口…

LeetCode | 不同路径

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。 问总共有多少条不同的路径? 示例 1…

低代码系统-产品架构案例介绍、得帆云(八)

产品名称 得帆云DeCode低代码平台-私有化 得帆云DeMDM主数据管理平台 得帆云DeCode低代码平台-公有云 得帆云DePortal企业门户 得帆云DeFusion融合集成平台 得帆云DeHoop数据中台 名词 概念 云原生 指自己搭建的运维平台,区别于阿里云、腾讯云 Dehoop 指…

使用ensp进行ppp协议综合实验

实验拓扑 实验划分 AR1的Serial3/0/0接口:192.168.1.1/24; AR2的Serial3/0/0接口:192.168.1.2/24; AR2的Serial3/0/1和4/0/0的聚合接口:192.168.2.2/24; AR3的Serial3/0/0和3/0/1的聚合接口:192…

【Python・机器学习】多元回归模型(原理及代码)

前言 自学笔记,分享给语言学/语言教育学方向的,但对语言数据处理感兴趣但是尚未入门,却需要在论文中用到的小伙伴,欢迎大佬们补充或绕道。ps:本文最少限度涉及公式讲解(文科生小白友好体质)&am…

unity免费资源2025-1-26

https://assetstore.unity.com/packages/tools/animation/motion-warping-climb-interact-270046 兑换码KINEMATION2025

Kitchen Racks 2

Kitchen Racks 2 吸盘置物架 Kitchen Racks-CSDN博客

ESMC-600M蛋白质语言模型本地部署攻略

前言 之前介绍了ESMC-6B模型的网络接口调用方法,但申请token比较慢,有网友问能不能出一个本地部署ESMC小模型的攻略,遂有本文。 其实本地部署并不复杂,官方github上面也比较清楚了。 操作过程 环境配置:CUDA 12.1、…

JAVA设计模式:依赖倒转原则(DIP)在Spring框架中的实践体现

文章目录 一、DIP原则深度解析1.1 核心定义1.2 现实比喻 二、Spring中的DIP实现机制2.1 传统实现 vs Spring实现对比 三、Spring中DIP的完整示例3.1 领域模型定义3.2 具体实现3.3 高层业务类3.4 配置类 四、Spring实现DIP的关键技术4.1 依赖注入方式对比4.2 自动装配注解 五、D…

JVM栈溢出线上环境排查

#查看当前Linux系统进程ID、线程ID、CPU占用率(-eo后面跟想要展示的列) ps H -eo pid,tid,%cpups H -eo pid,tid,%cpu |grep tid #使用java jstack 查看进程id下所有线程id的情况 jstack pid 案例2 通过jstack 排查死锁问题 #启动java代码 jstack 进…

Langchain+讯飞星火大模型Spark Max调用

1、安装langchain #安装langchain环境 pip install langchain0.3.3 openai -i https://mirrors.aliyun.com/pypi/simple #灵积模型服务 pip install dashscope -i https://mirrors.aliyun.com/pypi/simple #安装第三方集成,就是各种大语言模型 pip install langchain-comm…

Gradle配置指南:深入解析settings.gradle.kts(Kotlin DSL版)

文章目录 Gradle配置指南:深入解析settings.gradle.kts(Kotlin DSL版)settings.gradle.kts 基础配置选项单项目配置多项目配置 高级配置选项插件管理(Plugin Management)基础配置模板案例:Android项目标准配…

php twig模板引擎详细使用教程

php twig模板引擎 1. 什么是Twig模板引擎 Twig是一个强大且灵活的PHP模板引擎,它提供了一种更简洁和可扩展的方法来创建PHP应用程序的视图层。Twig模板引擎旨在将设计与业务逻辑分离,并为开发人员提供一种更加清晰和易于维护的方式来构建网页。Twig由S…

Java后端之AOP

AOP&#xff1a;面向切面编程&#xff0c;本质是面向特定方法编程 引入依赖&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency>示例&#xff1a;记录…

vim的多文件操作

[rootxxx ~]# vim aa.txt bb.txt cc.txt #多文件操作 next #下一个文件 prev #上一个文件 first #第一个文件 last #最后一个文件 快捷键: ctrlshift^ #当前和上个之间切换 说明&#xff1a;快捷键ctrlshift^&#xff0c…

DataSecOps的要点

2020年首次提出&#xff0c;DataSecOps是一种敏捷、全面、内置安全的 方法&#xff0c;用于协调不断变化的数据及其用户&#xff0c;旨在快速提供数据价值&#xff0c; 同时确保数据的私密性、安全性和良好的管理。 强调数据全生命周 期流转运营过程中的内嵌安全属性&#x…