volatile关键字解析

news2024/9/23 5:20:05

一、volatile介绍

        volatile是Java提供的一种轻量级的同步机制,在并发编程中,它也扮演着比较重要的角色。同synchronized相比(synchronized通常称为重量级锁),volatile更轻量级,相比使用synchronized所带来的庞大开销,倘若能恰当的合理的使用volatile,自然是美事一桩。

为了能比较清晰彻底的理解volatile,我们一步一步来分析。首先来看看如下代码

public class volatileDemo1 {
    static boolean flag = true;

    public static void main(String[] args) {
        new Thread(()->{
            System.out.println(Thread.currentThread().getName()+"\t -----come in");
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            flag = false;
        },"t1").start();

        new Thread(()->{
            System.out.println(Thread.currentThread().getName()+"\t -----come in");
            while (flag) {

            }
            System.out.println(Thread.currentThread().getName()+"\t -----flag被设置为false,程序停止");
        },"t2").start();
    }
}

        上面这个例子,模拟在多线程环境里,t1线程对flag共享变量修改的值能否被t2可见,即是否输出 “-----flag被设置为false,程序停止” 这句话?

        这个结论会让人有些疑惑,可以理解。因为倘若在单线程模型里,因为先行发生原则之happens-before,自然是可以正确保证输出的;但是在多线程模型中,是没法做这种保证的。因为对于共享变量flag来说,线程t1的修改,对于线程t2来讲,是"不可见"的。也就是说,线程t2此时可能无法观测到flage已被修改为false。那么什么是可见性呢?

​         所谓可见性,是指当一个线程修改了某一个共享变量的值,其他线程是否能够立即知道该变更,JMM规定了所有的变量都存储在主内存中。很显然,上述的例子中是没有办法做到内存可见性的。

  • 当写一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量值立即刷新回主内存中。
  • 当读一个volatile变量时,JMM会把该线程对应的本地内存设置为无效,重新回到主内存中读取最新共享变量。

        所以volatile的写内存语义是直接刷新到主内存中,读的内存语义是直接从主内存中读取,从而保证了可见性。

volatile变量有2大特点,分别是:

  • 可见性
  • 有序性:禁重排!

volatile不保证:

  1. volatile关键字 不具备【互斥性】
  2. volatile关键字 不能保证变量的【原子性】

        重排序是指编译器和处理器为了优化程序性能面对指令序列进行重新排序的一种手段,有时候会改变程序予以的先后顺序。

  • 不存在数据以来关系,可以重排序;
  • 存在数据依赖关系,禁止重排序。
  • 但重排后的指令绝对不能改变原有串行语义!

        那么volatile凭什么可以保证可见性和有序性呢?? ----内存屏障Memory Barrier~

二、内存屏障

​         内存屏障(Memory Barrier,或有时叫做内存栅栏,Memory Fence)是一种CPU指令,用于控制特定条件下的重排序和内存可见性问题。Java编译器也会根据内存屏障的规则禁止重排序。

​         Java中的内存屏障其实就是一种JVM指令,Java内存模型的重排规则会要求Java编译器在生成JVM指令时插入特定的内存屏障指令,通过这些内存屏障指令,volatile实现了Java内存模型中的可见性和有序性(禁重排),但volatile无法保证原子性。

  • 内存屏障之前 的所有 写操作 都要 回写到主内存,
  • 内存屏障之后 的所有 读操作 都能获得内存屏障之前的所有写操作的最新结果(实现了可见性)。

粗分主要是以下两种屏障:

  • 读屏障(Load Memory Barrier) :在读指令之前插入读屏障,让工作内存或CPU高速缓存当中的缓存数据失效,重新回到主内存中获取最新数据。
  • 写屏障(Store Memory Barrier) :在写指令之后插入写屏障,强制把写缓冲区的数据刷回到主内存中。

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

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

相关文章

Python 读取esxi上所有主机的设备信息

(主要是为了统计所有虚拟机的设备名称和所属主机) 代码: from pyVim import connect from pyVmomi import vim import ssldef get_vm_devices(vm):devices []try:if vm.config is not None and hasattr(vm.config, hardware) and hasattr(v…

JavaWeb入门程序解析(Spring官方骨架、配置起步依赖、SpringBoot父工程、内嵌Tomcat)

3.3 入门程序解析 关于web开发的基础知识,我们可以告一段落了。下面呢,我们在基于今天的核心技术点SpringBoot快速入门案例进行分析。 3.3.1 Spring官方骨架 之前我们创建的SpringBoot入门案例,是基于Spring官方提供的骨架实现的。 Sprin…

gite+picgo+typora打造个人免费笔记软件

文章目录 1️⃣个人笔记软件2️⃣ 配置教程2.1 使用软件2.2 node 环境配置2.3 软件安装2.4 gite仓库设置2.5 配置picgo2.6 测试检验2.7 github教程 🎡 完结撒花 1️⃣个人笔记软件 最近换了环境,没有之前的生产环境舒适,写笔记也没有劲头&…

R语言实现对模型的参数优化与评价KS曲线、ROC曲线、深度学习模型训练、交叉验证、网格搜索

目录 一、模型性能评估 1、数据预测评估 2、概率预测评估 二、模型参数优化 1、训练集、验证集、测试集的引入 2、k折线交叉验证 2、网格搜索 一、模型性能评估 1、数据预测评估 ### 数据预测评估 #### 加载包,不存在就进行在线下载后加载if(!require(mlben…

VMware Vsphere创建虚拟机

作者:红米 一、上传系统镜像 1、打开数据中心 2、新建文件夹,存放镜像 3、点击上传文件按钮 4、找到本地镜像上传 二、安装虚拟机 1、创建虚拟机 2、选择创建类型 3、为虚拟机命名并选择虚拟机安装的所在位置 4、选择计算资源 5、选择存储 6、选择兼容…

微服务

微服务 SpringCloud的五大组件 eureka服务注册和发现 nacos的工作流程 nacos和eureka的区别 负载均衡 ribbon负载均衡策略 如何自定义负载策略 服务雪崩 服务熔断 为服务端监控 项目中的限流 seata xa模式 AT模式 tcc模式 分布式服务接口幂等 分布式任务调度

2024年CSP-J暑假冲刺训练营(1):分析往年真题

考纲大览 一、往年真题1. 2019-2023 真题2. 整体分析 二、类型分析三、押题 一、往年真题 1. 2019-2023 真题 2. 整体分析 首先大家一定要明确,CSP-J 是不会给大家占便宜的,所以大家可以看到,即使被标注了"入门"难度的题目&#…

【性能测试】第二节.loadrunner工具介绍(LR)

文章目录 前言一、VUG:虚拟用户发生器 1.1 实现作用 1.2 创建一个新的性能测试脚本 1.3 打开LR自带的web系统 1.4 编写性能测试脚本流程方法 1.5 性能测试脚本的增强二、Controller 2.1 基础功能介绍 2.2 Design 2.3 Run三…

<Qt> 信号和槽

目录 一、信号和槽概述 二、信号和槽的使用​​​​​​ (一)connect函数 (二)实现一个点击按钮关闭窗口的功能 (三)再谈connect 三、自定义槽函数 四、自定义信号 五、带参数的信号和槽 六、信号…

Clonezilla 备份还原过程推送日志到 syslog

Clonezilla 备份、还原过程中,系统的运行日志只能显示到客户端显示器上,如果出现错误,无法在服务端查询到对应的日志,一是故障判断不太方便;另一方面,实现日志推送,也可以将 Clonezilla 运行进度…

【前端】ikun-qrcode:极简的二维码生成组件,使用view而非canvas避免层级问题

文章目录 背景ikun-qrcode界面效果如何发布一款自己的插件到uniapp市场。(5分钟搞定) 背景 之前在uniapp上100行搞定二维码生成, 现在封装为vue组件分享出来: 下载地址: https://ext.dcloud.net.cn/plugin?id19351 …

吐血整理如何在Google Earth Engine上写循环 五个代码实例详细拆解

引言 这篇文章主要解答GEE中.map()和.iterate()函数的用法。 首先解答一个疑问,为什么需要自己写循环?确实,GEE 为各种数据类型提供了无数常用的内置函数,对这些方法做排列组合足以应对大多数使用场景,算法效率也颇佳。…

台风预警新选择:太阳能LED宣传信号杆

台风预警新选择:太阳能LED宣传信号杆 以下是对台风灾害的严重性、传统预警方式的不足以及太阳能台风预警宣传信号杆的出现和优势等方面进行分析和归纳: 一、台风灾害的严重性 台风作为一种强烈的自然灾害,给沿海地区带来了极大的威胁。台风…

【数学建模】——【线性规划】及其在资源优化中的应用

目录 线性规划问题的两类主要应用: 线性规划的数学模型的三要素: 线性规划的一般步骤: 例1: 人数选择 例2 :任务分配问题 例3: 饮食问题 线性规划模型 线性规划的模型一般可表示为 线性规划的模型标准型&…

论文学习——基于自适应选择的动态多目标进化优化有效响应策略

论文题目:Effective response strategies based on adaptive selection for dynamic multi-objective evolutionary optimization 基于自适应选择的动态多目标进化优化有效响应策略(Xiaoli Li a,b,c, Anran Cao a,∗, Kang Wang a)Applied S…

活动报名 | 智源研究院数据与行业应用Workshop

7月25日周四下午14点,智源人工智能研究院将联合中国互联网协会人工智能工委会、中国AIIA联盟数据委员会、共同举办数据与行业应用 Workshop~ 届时,智源的技术专家将介绍行业数据集和千万级指令微调数据集的构建思路和获取方法。更有来自北京…

【QGroundControl二次开发】二.使用QT编译QGC(Windows)

【QGroundControl二次开发】一.开发环境准备(Windows) 二. 使用QT编译QGC(Windows) 2.1 打开QT Creator,选择打开项目,打开之前下载的QGC项目源码。 编译器选择Desktop Qt 6.6.3 MSVC2019 64bit。 点击运…

Java项目打包成exe

文章目录 1.使用 exe4j 工具2.导出 jar 包3.转化 1.使用 exe4j 工具 安装激活: https://www.cnblogs.com/jepson6669/p/9211208.html 2.导出 jar 包 使用 mvn 的 package 导出默认没有依赖包,这里从 IDEA 的 Artifacts 导出。 // 导出路径为了方便…

鱼眼相机变普通相机,利用Transform进行球面变换

Abstract 高分辨率广角鱼眼图像在自动驾驶等机器人应用中变得越来越重要。然而,使用普通的卷积神经网络或视觉变换器处理这类数据时会遇到问题,因为在将其投影到平面上的矩形网格时会引入投影和失真损失。为了解决这个问题,我们引入了HEAL-S…

强化学习的数学原理(2)

Value iteration & Policy itreation Value iteration algorithm 之前我们已经讲过怎么去求解贝尔曼最优公式,是利用contraction mapping theorem 来进行求解,我们知道这个contraction mapping theorem是一个迭代算法,实际上这个算法他有…