首页 星云 工具 资源 星选 资讯 热门工具
:

PDF转图片 完全免费 小红书视频下载 无水印 抖音视频下载 无水印 数字星空

Volatile关键字

编程知识
2024年08月20日 22:17

背景

volatile关键字是并发编程中的一个比较重要的关键字。它能保证变量/对象在内存中的可见性,同时禁止指令重排序,避免了CPU或者编译器优化带来的可见性问题。
在并发编程中,volatile可以去修饰一个变量,或者是一个对象(比如单例模式中就使用了volatile去修饰单例对象)
举例说明

volatile int a = 100;
volatile SingleInstance instance;* 

什么是可见性?什么是可见性问题?

答: 可见性指的是一个共享变量被线程修改了以后,其他线程能立即看到变更后的变量值。因为线程是在各自的工作内存中执行数据的逻辑操作,并不会操作到主内存的变量值,一旦线程更新了变量的值,如果想要被可见,就必须立即再更新至主内存。所以,可见性问题就是指,A线程更新了变量的值,其他B线程操作变量的时候,没有得到这个变量变更后的新值,也就是A线程修改的值不可见。B线程使用旧值对变量进行更新操作,从而使得数据不一致。这个就是可见性问题!

如何解决变量可见性问题?

答:java中解决可见性问题的方案有很多。比如synchronzied, volatile, Lock锁,Atomic包下的原子类,JUC下的类。
synchronzied主要是保证同一时刻只能有一个线程操作某一个共享变量。避免多个线程同时访问一个共享变量带来的可见性问题。
volatile主要是会确保每个线程都能从主内存中读取该变量的最新值,而不是从自己的缓存中读取。本篇文章主要讲volatile的底层原理。

volatile的实现原理

volatile是通过内存屏障来禁止指令重排序,从而保证可见性的。
内存屏障有写屏障和读屏障(这些屏障实际上是一些硬件或者编译器级别的指令), volatile变量更新以后,会立即调用store指令,确保之前所有的写操作都会刷新到主内存中,避免写操作的重排序。读屏障确保读取volatile变量之前,会从主内存中读取最新的值。大多数处理器用的都是StoreLoad屏障。
StoreLoad相当于是一个全屏障,它会把处理器给变量赋值的指令存储到Store Buffer, 然后lock指令使到Store Buffer中的数据刷新到缓存行,同时使得其他CPU缓存了变量的缓存行失效。
所以说内存屏障底层其实还是调用了Lock指令。

happens before模型

这个JMM中的一些规范,主要是描述了两个操作指令的顺序关系。如果A操作和B操作存在happens-before的关系,那么意味着A操作的执行结果对B操作可见。
以下是一些Happens-before规则

Happens-before规则

  • 程序顺序原则
    在同一个线程中,如果x操作在Y操作之前,那么x happens before y,其实也是as-if-serial语义。
  • 传递性规则
    如果存在A happens before B; B happens before C, 那么必然会存在A happens before C 。
  • volatile变量规则
    指的是通过内存屏障来保障一个volatile修饰的变量的写操作一定happens before于其读操作。
  • 监视器锁规则
    一个线程对一个锁的释放操作一定happens before后续线程对该锁的加锁操作。
public void monitor() {
  synchronzied(this) {
  if(x == 0) {
    x = 10;
  }
}

如代码所示,当A线程执行逻辑之前,加上锁,执行结束后,会释放锁,此时A产生的结果对B一定是可见的。

  • start规则
    假如一个线程A调用子线程的start方法,那么线程A在调用start()方法之前的所有操作都happens-before线程B中的所有操作。
  • join规则
    首先join()的作用是等待某个子线程的执行结果。
    如果主线程main()执行了线程A的join()方法并且成功返回,那么线程A中的任意操作happens before 于main线程的join()方法返回之后的操作。
From:https://www.cnblogs.com/xyuanzi/p/18370414
本文地址: http://www.shuzixingkong.net/article/1284
0评论
提交 加载更多评论
其他文章 async await 状态机理解
public async Task<string> Wait3S() { await Task.Delay(3000); Console.WriteLine("Wait 3 S"); return ""; } #region 异步任务-状态机 #i
Java微信授权登录小程序接口
1.微信授权登录小程序的流程是什么 微信授权登录小程序的流程是一个涉及前端和后端交互的过程,主要目的是让用户能够使用微信账号快速登录小程序,避免重复输入用户名和密码。以下是该流程的详细步骤: 1.1前端操作 (1)触发登录: 用户在小程序中点击“登录”按钮或进入需要登录的页面时,系统会自动弹出授权登
RabbitMQ 基础概念与架构设计及工作机制学习总结
什么是RabbitMQ MQ全称为Message Queue,即消息队列. 它也是一个队列,遵循FIFO原则 。RabbitMQ则是一个开源的消息中间件,由erlang语言开发,基于AMQP协议实现的一个软件产品,提供应用程序之间的通信方法,在分布式系统开发中广泛应用。 AMQP协议 AMQP,即A
RabbitMQ 基础概念与架构设计及工作机制学习总结 RabbitMQ 基础概念与架构设计及工作机制学习总结 RabbitMQ 基础概念与架构设计及工作机制学习总结
WPF:静态、动态资源以及资源词典
WPF:静态、动态资源以及资源词典 静态资源与动态资源 我们常常会使用样式或者控件模板放在Window.Resources中,比如这样: 静态资源与动态资源使用如下: <Window.Resources> <SolidColorBrush x:Key="SolidColo
WPF:静态、动态资源以及资源词典 WPF:静态、动态资源以及资源词典 WPF:静态、动态资源以及资源词典
BST 二叉搜索树 BinarySearchTree C++实现(递归/非递归)
目录二叉搜索树基本概念常用结论用途二叉搜索树的性能分析二叉搜索树的操作查找插入删除代码实现BSTree.hpptest.cc 二叉搜索树 基本概念 二叉搜索树(BST,Binary Search Tree) 二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树: 若它的左子树不为空
BST 二叉搜索树 BinarySearchTree C++实现(递归/非递归) BST 二叉搜索树 BinarySearchTree C++实现(递归/非递归) BST 二叉搜索树 BinarySearchTree C++实现(递归/非递归)
变分信息瓶颈 (Variational Information Bottleneck) 公式推导
互信息 互信息用于表示两个随机变量相互依赖的程度。随机变量 \(X\) 和 \(Y\) 的互信息定义为 \[\begin{aligned} I(X, Y) & = \mathrm{KL}[p(\boldsymbol{x}, \boldsymbol{y}) \parallel p(\bolds
变分信息瓶颈 (Variational Information Bottleneck) 公式推导
[rCore学习笔记 025]分时多任务系统与抢占式调度
写在前面 本随笔是非常菜的菜鸡写的。如有问题请及时提出。 可以联系:1160712160@qq.com GitHhub:https://github.com/WindDevil (目前啥也没有 本节重点 本章最开始的时候讲解了有类似于多道程序与协作式调度的区别. 回想上一节,我们提到的,如果我们仍然
[rCore学习笔记 025]分时多任务系统与抢占式调度
C#二叉搜索树算法
二叉搜索树算法实现原理 二叉搜索树(Binary Search Tree,简称BST)是一种节点有序排列的二叉树数据结构。它具有以下性质: 每个节点最多有两个子节点。 对于每个节点,其左子树的所有节点值都小于该节点值,其右子树的所有节点值都大于该节点值。 实现基本步骤和代码示例 步骤 定义节点类:包
C#二叉搜索树算法 C#二叉搜索树算法