深度理解volatile关键字

2023-10-28

Volatile

java中可以把字段声明为volatile的。比如:

public class AtomicInteger extends Number implements java.io.Serializable {
   // volatile变量
   private volatile int value;
}

但是volatile启什么作用呢?

作用

这里先说结论:

  1. volatile关键字是并发编程的时候来保证可见性
  2. 简单讲就是线程A修改完volatile字段,线程B立即来读的话,是能读到最新的值的。

这里面有个问题,就是问什么会有可见性的问题?

CPU多级缓存

CPU为了加快处理数据的速度,加入了缓存,加缓存的原则,依赖于局部性原理:

  1. 时间局部性
    某个数据项被访问后,可能很快会被再次访问的特性。
  2. 空间局部性
    某个数据项被访问后,与其地址相近的数据项可能很快被访问的特性。

我们可以利用局部性原理将计算机的存储器组织成为存储器层次结构

在这里插入图片描述

缓存的最小单位是缓存行(cache line),现在主流的CPU缓存行是 64bytes
Linux 系统可以通过cat /sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size命令查看缓存行大小。
Mac 系统可以通过sysctl hw.cachelinesize查看缓存行的大小。

缓存一致性问题 Cache coherence

cpu缓存模型,其实默认情况下是有问题的,特别是多线程并发运行的时候,导致各个cpu的本地缓存跟主内存没有同步,一个数据在各个地方可能都不一样,就会导致数据的不一致问题。
在这里插入图片描述

缓存一致性协议

这里限于文章篇幅,和突出文章主题,不展开讲了。
一句话就是,现在主流的CPU都是通过MESI协议来解决缓存一致性问题的。

Java怎么实现的?

java规范手册

我们先看一下java规范手册对volatile的描述。
在这里插入图片描述
注意上图中红框框里面的文字,也就是说,java规范里面有个happens-before的原则。规则中约定了哪些动作在实际运行过程中要发生于哪些动作之前。而volatile声明的字段就在happens-before的原则里面。

这是在语言层面做的规约,那么实际JVM中又是怎么实现的呢?

class文件&CPU指令

以hotspot为例,先看一下volatile声明的字段在class文件是什么样子的
添加volatile

int v;
  descriptor: I
  flags:

添加volatile

volatile int v;
  descriptor: I
  flags:ACC_VOLATILE

class文件中变量flags: ACC_VOLATILE

通过 jitwatch 工具查看,运行过程中CPU实际执行的指令是啥呢?
我们发现,加了volatile的变量,在保存的时候
多了一行汇编指令lock addl $0x0,(%rsp)

查询 IA32 手册:

在这里插入图片描述
在这里插入图片描述

简述一下原文的要点:
在执行相应指令时,使处理器的LOCK#信号被激活(将指令转换为原子指令)。在多处理器环境中,LOCK#信号确保在信号被激活期间,处理器独占任何共享内存

限制使用的命令ADD, ADC, AND, BTC, BTR, BTS, CMPXCHG, CMPXCH8B, CMPXCHG16B, DEC, INC, NEG, NOT, OR, SBB, SUB, XOR, XADD, XCHG.

总结下来就是lock前缀指令 + 缓存一致协议来实现的

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

深度理解volatile关键字 的相关文章

  • Java-线程与CPU的关系

    我对多线程还很陌生 我正在开发一个项目 尝试在我的 Java 程序中使用 4 个 CPU 我想做类似的事情 int numProcessors Runtime getRuntime availableProcessors ExecutorS
  • 在 IntelliJ 上进行 Google App Engine Java 开发?

    令人烦恼的是 Google App Engine 已成为其中的另一个项目 他们只发布 Eclipse 插件 如 Spring Webflow 而我更喜欢 IntelliJ 你能用IntelliJ成功运行本地测试环境吗 并调试 部署本地或实时
  • 使用 Android WebViewClient 启用特定 SSL 协议

    我的应用程序使用WebViewClient与服务器建立 SSL 连接 服务器配置为仅接受 TLSv1 1 及以上协议 使用 Android 时 如何检查哪些 SSL 协议是 a 支持的和 b 默认启用的WebViewClient在设备上 如
  • 使用 jpql 和 jpa 从日期字段中提取年份

    我想从数据库中的一行中提取年份部分 以便将其与值进行比较 这是我的功能 public List
  • firebase推送通知错误Spring Boot服务器端

    我正在尝试从 Spring Boot 服务器端发送通知到客户端 android 服务器运行良好 一切都很好 2020 09 01 08 13 07 691 INFO 18941 restartedMain e DevToolsPropert
  • 如果基于 Spring 注解的控制器位于 jar 文件内,则该控制器无法工作

    我的子模块中有一些基于注释的控制器 这些模块作为 jar 文件部署 jar 文件中基于注释的控制器未加载到 spring 配置中 我使用 Eclipse 中的导出实用程序手动导出 jar 文件 有人遇到过这个问题吗 当您使用 Eclipse
  • 正确使用 JDBC 连接池 (Glassfish)

    我需要在 Java Web 服务中作为会话 bean 实现数据库连接 但我不确定我这样做是否正确 我创建了一个类 public final class SQLUtils private static DataSource m ds null
  • 支持通过 OAuth 进行 Facebook/Twitter 身份验证的 CAS 服务器

    我正在寻找一个支持 Facebook Twitter 通过 OAuth 进行单点登录身份验证的 CAS 服务器 我检查过 JASIG CAS 服务器 但它看起来不支持它们 我的 java web 应用程序基于 Spring Security
  • 从 sbt 程序集运行 uber jar 会导致错误:无法找到或加载主类

    我有一个使用 sbt 程序集插件打包为 uber jar 的 Spark 作业 这build sbt指定一个可运行的 main 作为生成的 uber jar 的目标 mainClass in assembly Some com foo Ba
  • Java元数据读写

    是否可以以通用方式 对于所有图像类型 在 Java 中读取和写入元数据 我找到了一些示例 但它们总是特定的 例如 JPEG 或 PNG 我需要一些足够通用的东西 而不是到处都有 if else 语句 我不想重写源代码 但这是一个很好的例子
  • 不要模拟值对象:过于通用的规则,没有解释

    以下是 Mockito 单元测试框架的引用 不要模拟值对象 为什么有人会想要这样做呢 因为实例化对象太痛苦了 gt 无效 原因 如果创造新的装置太困难 那就是一个迹象 代码可能需要一些认真的重构 另一种方法是创建 价值对象的构建者 有一些工
  • Java:使用 Java.util.concurrent 线程访问读取线程串行端口

    我正在尝试编写一个 Java 串行设备驱动程序并想使用 对我来说是新的 java util concurrent包裹 我有一种发送数据包然后等待 ACK 的方法 我打算有炭 接收在不同的线程中运行 如果接收线程收到 ACK 它应该使用发送数
  • 在 eclipse 之外将 Spring MVC 应用程序部署到 tomcat 的幕后会发生什么?

    我猜想使用像 eclipse 这样很棒的 IDE 的一个缺点是你会忽略应用程序幕后发生的事情 我是一名 Ruby 开发人员 所以不是一名 Java 老手 所以我一直在用 java 编写一个项目 并使用 spring 框架进行 IOC 和 M
  • 使用Java开发跨平台,不同平台字体缩放不同

    我正在为我的大学制作一些软件 需要一个 GUI 在它的第一个版本中 我让它使用系统外观 因此它看起来像 Linux Mac Windows 中的本机应用程序 我发现这很麻烦 因为我必须根据操作系统使所有 JLabel 具有不同的大小 无论分
  • 无法映射 ftl 文件中的 jsonRequest 属性

    我想在 FTL 文件中映射下面的 json 文件市场和子市场字段 但是当我尝试下面的代码时 它没有映射 有人可以帮助我吗 我从 2 天开始就无法映射它 Json请求 ProcessOrderRequest prevalidationMode
  • 找不到符号assertEquals

    我正在尝试为计算器编写第一个单元测试 但 NetBeans 说它找不到该符号assertEquals和注释 Test 我应该包括一些东西吗 我正在使用 NetBeans 7 3 1 和 W7 package calculator impor
  • 读/写带有特殊字符的.txt文件

    I open Notepad Windows 并写 Some lines with special characters Special 并前往另存为 someFile txt 与Encoding set to UTF 8 在Java中我有
  • Selenium - 等待网络流量

    我们将 Selenium 与 Java API 和一些 Javascript 用户扩展一起使用 我们在应用程序中使用了大量 AJAX 调用 我们的许多测试随机失败 因为有时 AJAX 调用完成得比其他时候慢 因此页面未完全加载 我们通过等待
  • JMockit - 初始化问题

    当我使用以下测试时 我收到警告 警告 JMockit 是按需初始化的 这可能会导致某些测试失败 请检查文档以获取更好的初始化方法 这是我的测试实现 package test import static mockit Mockit impor
  • 我找不到 IntelliJ 快捷方式

    我使用 vim 一段时间 我知道有一个 intellij vim 插件 我很好奇内置的 IntelliJ 文本导航存在什么 如何打开实时模板来创建模板 如何查看以 tr 开头的现有模板列表 如何进行全局搜索并在当前文档中进行搜索 然后转到下

随机推荐

  • chmod 777 是什么意思

    您正在尝试修复您的Web服务器的权限问题 并在互联网上找到了信息 说您需要递归chmod 777网络目录 在此之前 请确保您了解什么是chmod R 777这样做 以及为什么永远不应该将权限设置为 777 本文解释了基本的 Linux 权限
  • 为什么更推荐使用组合而非继承关系?

    前言 最近在看公司项目的代码 看到了大量的继承体系 而且还是继承了多层 维护 阅读都十分的困难 在查阅了一些资料以后 包括 Effective Java 一书中的第16条提到 组合优先于继承 那继承到底会暴露什么问题呢 为什么更推荐优先使用
  • Arduino搭建盲猜数字小游戏

    1 本文整理自视频 太极创客 零基础入门学用Arduino 第一部分 合辑 需要的硬件 一个Arduino Uno开发板 一个200 500欧姆电阻 一个共阴极数码管 一个按键 数条杜邦线 跳线 2 显示数字其实就是显示各个数码管 注意需要
  • 重温Linux内核:互斥和同步

    文章目录 互斥和同步 1 前言 2 概念 2 1 竞态 2 2 共享资源 临界资源 2 3 造成竞态的根本原因 3 并发分类 解决竞态的方法 4 中断屏蔽 5 原子变量 5 1 定义 5 2 实现原理 5 3 API 5 4 注意事项 6
  • 开发踩坑日常 (parseInt进制转换,文字方向、换行,代理请求,xlsx)

    日常踩坑填坑 js进制转换 刚发现有同学没搞清楚这个 parseInt number 进制数 将任意进制 转换 为十进制 强调一下 第二个参数 是形容第一个参数是什么进制的 并不是转换的目标进制 这里贴一下W3C 的文档说明 https w
  • 【转载】windows和wls文件互通

    windows和wls文件互通 wsl访问windows文件 https www jianshu com p d332e05adb6f windows访问wsl文件 https blog csdn net Caoyang He articl
  • Android 之 WebView (网页视图)基本用法

    本节引言 本节给大家带来的是Android中的一个用于显示网页的控件 WebView 网页视图 现在Android应用 层开发的方向有两种 客户端开发和HTML5移动端开发 所谓的HTML5端就是 HTML5 CSS JS来构建 一个网页版
  • TCPIP技术实验大作业:基于TCP/IP的程序开发技术综述及应用实践

    一 基于TCP IP的程序开发技术综述 1 1TCP IP协议族简介 TCP IP也被称作传输控制协议 网际协议 作为网络互连的核心协议 受到广泛的应用 该协议类型作为开放性的标准应用在各种计算机中 在一定程度上保证系统间通信的正常运行 在
  • mysql replication环境检查脚本

    author skate time 2013 05 13 mysql replication环境检查脚本 此脚本部署在slave端 可以通过短信或邮件监控slave的mysqld健康 replication环境健康 及复制延迟 脚本 mys
  • monorepo 下的 package tsc 构建

    很多个package都需要构建到每个项目的 lib 下 可以用 vscode 的 tasks json 任务去实现 具体 tasks json 的详情请看官网 https code visualstudio com docs editor
  • JavaScript中字符串的大小写转换(轮子,直接cv即可)

    此文件为js文件 封装模块按需导出即可 str 需要首字母转换的字符串 全部大写 export const all2Large str gt const arr str split let newStr 通过数组的forEach方法来遍历数
  • 解决Ubuntu下 anaconda 与ros opencv冲突的问题

    解决Ubuntu下 anaconda 与ros opencv冲突的问题 问题描述 解决办法之一 问题描述 在Ubuntu16 04上先后安装了Anaconda和ROS 然后在anaconda配置的pytorch环境中运行python代码 在
  • 【毕设】基于CycleGAN的风格迁移【一】环境搭建及运行代码

    源代码地址 CycleGAN源码 因为该篇内容包含Anaconda的环境管理及包的管理 可以选择参考 Anaconda安装 环境管理 包管理 实际演练例子 全网最详细 MrRoose1的博客 CSDN博客 一 搭配环境 1 首先把代码包下载
  • 递归、回溯-图的m着色问题

    1 问题描述 给定无向连通图G V E 和m种不同的颜色 用这些颜色为图G的各顶点着色 每个顶点着一种颜色 是否有一种着色法使G中每条边的2个顶点着不同颜色 这个问题是图的m可着色判定问题 输入 图的顶点的个数 颜色种类树m 输出顶点a与顶
  • C

    我们想定义一个全局变量 能够在多个文件中使用 举例说明比如说三个文件main c hello c hello h 想在main c和hello c中使用一个名字为a的变量 可能大家会简单地想直接在hello h里面定义一个变量unsigne
  • 网站渗透测试 越来越难渗透

    福利 网络安全重磅福利 入门 进阶全套282G学习资源包免费分享 最先 对于大家提出的难题 网站愈来愈难渗透 表明如今的安全防护技术性及其网站结构技术性的成熟情况是越来越健全了 次之 某一实际技术性方面的安全要求减少了 不可以整体表明渗透测
  • 分页组件的使用-jqPaginator

    工作中用到了分页 在github上面用到了一款分页组件 是叫jqPaginator 参考网站是 http jqpaginator keenwon com a3 上面可以下载 以及介绍怎么使用 贴出我使用的例子的代码 html div cla
  • 2020最新大厂高频微服务面试总结:Spring-Cloud+Spring-Boot+Dubbo(面试题+笔记+项目实战)

    话不多说 直接上题 SpringCloud面试题 什么是 Spring Cloud 使用 Spring Cloud 有什么优势 服务注册和发现是什么意思 Spring Cloud 如何实现 Spring Cloud 和dubbo区别 Spr
  • Linux MySQL 常见无法启动或启动异常的解决方案

    Linux MySQL 常见无法启动或启动异常的解决方案 在 Linux 上自建 MySQL 服务器 经常遇到各种无法启动或启动后异常的问题 本文列举一些常见问题的解决办法 注意 以下错误日志提示 都是查看 MySQL 错误日志得到 查看方
  • 深度理解volatile关键字

    Volatile java中可以把字段声明为volatile的 比如 public class AtomicInteger extends Number implements java io Serializable volatile变量