了解 Java 中同步块与易失性变量的原子性、可见性和重新排序

2024-01-10

我试图理解volatile《Java 并发实践》一书中的关键字。我比较synchronized关键字与volatile变量在三个方面:原子性、波动性和重新排序。我对此也有一些疑问。我在下面一一讨论过:

1) 可见性:“同步”与“易变”

书上说以下关于可见性synchronized:

一切线程A在同步块中或之前执行的操作对于B当它执行由同一锁保护的同步块时。

它说以下关于可见性volatile变量:

易失性变量不会缓存在寄存器或缓存中,对其他处理器隐藏,因此对易失性变量的读取始终返回任何线程的最新写入。
易失性变量的可见性影响超出了 易失性变量本身。当线程 A 写入易失性变量并且随后线程 B 读取同一变量时,在写入易失性变量之前对 A 可见的所有变量的值在读取易失性变量后对 B 来说都可见。因此,从内存可见性的角度来看,写入易失性变量就像退出同步块,读取易失性变量就像进入同步块。

Q1.我觉得上面第二段(的volatile)对应于书上所说的内容synchronized。但有没有synchronized-相当于volatile的第一段?换句话说,是否使用synchronized确保任何/某些变量不会缓存在处理器缓存和寄存器中?

请注意,这本书还提到了以下关于可见性的内容synchronized:

锁定不仅仅意味着互斥,还意味着互斥。它还与内存可见性有关。

2)重新排序:“同步”与“易失性”

书上说以下内容volatile在重新排序的情况下:

当一个字段被声明时volatile,编译器和运行时会注意到该变量是共享的,并且对其进行的操作不应与其他内存操作重新排序。

Q2.本书没有提及任何有关重新排序的内容synchronized。有人可以解释一下在以下情况下可以说的重新排序吗synchronized?

3)原子性

书上说以下关于原子性synchronized and volatile.

易失性的语义不够强大,无法进行增量操作(count++) 原子性,除非你能保证该变量仅从单个线程写入。

加锁可以同时保证可见性和原子性;易失性变量可以 只保证可见性。

Q3.我想这意味着两个线程可以看到volatile int a两者一起都会增加它然后保存它。但只有最后一次读取才会生效,从而使整个“读取-增量-保存”成为非原子的。我对非原子性的解释是否正确volatile?

Q4.是否所有等价锁都是可比较的,并且具有相同的可见性、顺序和原子性属性:同步块、原子变量、锁?

PS:这个问题与完全修改的版本有关this https://stackoverflow.com/questions/60931421/lock-vs-synchronized-vs-atomic-variables-vs-volatile-in-java-in-terms-of-read-wr?noredirect=1#comment107849085_60931421几天前我问过的问题。自从全面改版以来,我还没有删除旧的。我以更加集中和结构化的方式写了这个问题。一旦我得到这个问题的答案,就会删除旧的。


“同步”和“易失性”之间的主要区别在于,“同步”可以使线程暂停,而易失性则不能。

“缓存和寄存器”不是一回事。书中这样说是因为在实践中这通常是事物的实现方式,并且它使得更容易(或者可能不是,考虑到这些问题)理解 JMM(java 内存模型)的方式和原因。

不过,JMM 并没有透露他们的名字。它所说的只是虚拟机可以自由地为每个线程提供其自己的任何变量的本地副本,或者不,在任意时间与一些或所有其他线程同步,或者不......unless任何地方都存在事前发生的关系,在这种情况下,VMmust确保在两个线程之间的执行点发生在之前关系已经建立,他们观察到所有变量都处于同一状态。

实际上,这可能意味着刷新缓存。或不;这可能意味着另一个线程覆盖其本地副本。

虚拟机可以随意实现这些东西,而且在每个架构上都有不同的实现方式。只要 VM 坚持 JMM 做出的保证,它就是一个很好的实现,因此,您的软件必须仅在这些保证且没有其他假设的情况下工作;因为如果您依赖 JMM 无法保证的假设,那么在您的计算机上有效的内容可能在另一台计算机上无效。

重新排序

重新排序也不在 VM 规范中。 VM 规范中包含以下两个概念:

  1. 在单个线程的范围内,您可以从内部观察到的所有内容都与有序视图一致。也就是说,如果你写 'x = 5; y = 10;'从同一线程内不可能观察到 y 为 10 但 x 为其旧值。无论同步还是易失。所以,它可以随时重新排序而不是可观察到的,那么虚拟机就可以自由活动了。会吗?直到虚拟机。有些会,有些不会。

  2. 当观察由其他线程引起的效果时,并且您尚未建立发生之前关系,您可能会以任何顺序看到部分、全部或没有这些效果。真的,这里什么事情都有可能发生。在实践中,那么:不要尝试在没有建立发生之前的情况下观察其他线程引起的效果,因为结果是任意的并且不可测试的.

发生在关系是由各种事物建立的;同步块显然可以做到这一点(如果您的线程在尝试获取锁时被冻结,然后它运行,该对象上完成“之前发生”的任何同步块,以及它们所做的任何事情您现在都可以观察到,并保证您所做的事情观察与那些按顺序运行的事物一致,并且您可以看到它们写入的所有数据(例如,您不会获得较旧的“缓存”或诸如此类的东西)。易失性访问也是如此。

原子性

是的,即使 x 是易失性的,您对为什么 x++ 不是原子的解释是正确的。

我不确定你的 Q4 想问什么。

一般来说,如果您想以原子方式递增一个整数,或者执行任何其他并发操作,请查看java.util.concurrent包裹。它们包含各种概念的有效且有用的实现。原子整数 https://java-browser.yawk.at/java/14/java.base/java/util/concurrent/atomic/AtomicInteger.java#java.util.concurrent.atomic.AtomicInteger例如,可用于以对其他线程可见的方式原子地递增某些内容,同时仍然相当高效(例如,如果您的 CPU 支持比较与设置 (CAS) 操作,Atomicinteger 将使用它;如果不求助于一般java,你就无法做到这一点Unsafe).

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

了解 Java 中同步块与易失性变量的原子性、可见性和重新排序 的相关文章

  • 使用 Nginx 时缺少 HTTP 状态代码名称

    我正在使用 Nginx 将所有 HTTP 请求重定向到 HTTPS 在我的 Spring Boot 应用程序中 这是我正在使用的 nginx 配置 通过它我可以将所有请求重定向到 Https 但是当我这样做时 我得到了状态码返回正确 但没有
  • 为什么byteArray的长度是22而不是20?

    我们尝试从字符串转换为Byte 使用以下 Java 代码 String source 0123456789 byte byteArray source getBytes UTF 16 我们得到一个长度为 22 字节的字节数组 我们不确定这个
  • 为什么 hibernate 在一张表中保存两个 @OneToMany 列表?

    想象一下使用 Hibernate 和 JPA 的简化代码如下 Entity class C Id GeneratedValue public long id MappedSuperclass abstract class A Id Gene
  • 术语“引用”的起源,如“通过引用传递”

    Java C 语言律师喜欢说他们的语言按值传递引用 这意味着 引用 是调用函数时复制的对象指针 同时 在 C 中 以及 Perl 和 PHP 中更动态的形式 引用是其他名称 或动态情况下的运行时值 的别名 我对这里的词源感兴趣 参考 一词的
  • 使用 google-api-java-client 的 2 足 OAuth

    有谁知道如何将 2 legged OAuth 与 google api java client 一起使用 我正在尝试访问 Google Apps 配置 API 以获取特定域的用户列表 以下不起作用 HttpTransport transpo
  • 通过 JDBC 连接到 DB2 时的用户和密码

    我正在尝试连接到本地 DB2 10 5 Express C 服务器 这是一个测试环境 所以我不关心安全性 我能够连接到命令行处理器 在 Windows 上运行 并且我更改了配置设置AUTHENTICATION CLIENT and TRUS
  • 如何避免 Java 中的忙旋转

    我有一个多线程应用程序 其中一个线程向另一个线程发送消息 等待线程轮询消息并做出反应 处理锁 像这样 等待线程代码 while true if helloArrived System out println Got hello if bye
  • JFreeChart - 创建移动图表时出现问题

    我在我的 java 应用程序中使用 JFreeChart Problem 我想绘制一个XY面积图 whose 域轴 x 轴 当我们开始绘制数据时应该自动水平滚动 我在中看到了同样的事情时间序列图表但我不想要任何时间系列图表 我只想要滚动的
  • Java 中支持多少维数组,例如 a[1][1][1][1]....[1]? [复制]

    这个问题在这里已经有答案了 Java支持多少维数组a 1 1 1 1 1 我可以为数组声明无限数量的维度吗 数组维数限制为 255 有趣的是 JLS定义的Java编程语言没有这样的限制 但是你可以在JVM规范 http docs oracl
  • @Cachable 在没有输入参数的方法上?

    我有问题 org springframework cache annotation Cachable注解 Bean public ConcurrentMapCache cache return new ConcurrentMapCache
  • 竞争性编码 - 以最低成本清除所有级别:未通过所有测试用例

    当我遇到这个问题时 我正在一个竞争性编码网站上解决问题 问题指出 游戏中有 N 个关卡和 M 种可用武器 等级编号从 0 到 N 1 武器编号从 0 到 M 1 您可以按任意顺序清除这些级别 在每个关卡中 需要这些 M 武器的某些子集才能通
  • 整数与 int 比较

    我是新来的java 我现在正在学习非原始整数类型java 我知道以下比较无效并引发编译错误 String str c Char chr c if str chr return true 上面的代码片段给了我 Test java lineNu
  • 在 Java Swing 元素中使用 HTML 样式是不好的做法吗?

    使用 HTML 设置 Swing 元素的样式被认为是不好的做法吗 举个例子 如果我想让标签变大并变红一次 我有两个选择 使用 API 调用 JLabel label new JLabel This is a title label setF
  • Spring Boot 多部分文件始终为 null

    我正在使用 Spring Boot version 1 4 0 RC1 和 Spring Boot Stormpath 1 0 2 我正在尝试使用分段文件上传 但控制器中的 MultipartFile 始终为空 当我使用 RequestPa
  • 读取不失真的灰度 PNG 图像文件

    我需要读取和处理大量的灰度 PNG 文件 我的意思是 如果它们在 Photoshop 或 GIMP 中打开 则图像模式为灰度 而不是具有灰度值的 RGB 图像 ImageIO 似乎没有实现这一点 它似乎将所有图像文件视为 sRGB 这会破坏
  • Elasticsearch NodeBuilder 与 TransportClient

    对于其他 Elasticsearch 开发人员来说 这可能是一个非常简单 而且愚蠢 的问题 这两者之间有什么区别 我正在从 Java Web 应用程序连接到远程 Elasticsearch 服务器 到目前为止我一直在使用 Transport
  • 如何在不同的班级中启动和停止计时器?

    我想测量从传入 HTTP 请求开始到应用程序到达某个点的时间 这两个时间点都位于不同的类中 我将如何启动和停止这些不同类别的计时器 我没有看到使用 MeterRegistry 中的 命名 计时器的方法 我该怎么办呢 您可以使用 AOP 如下
  • 将字符串转换为字符并按降序排序(ascii)

    我正在创建一个程序 该程序将使用户输入整数 一个接一个 存储在数组中并按降序显示整数 该程序还要求用户输入一个字符串 使用以下命令将其转换为字符string toCharArray 我已经正确地按降序显示整数 问题是我不知道如何按降序显示字
  • 如何从Java中的连接获取查询字符串?

    我正在编写一个方法 尝试记录数据库调用 形成连接到它的连接 在查询之后 有很多地方调用方法 connect 来启动并调用 cleanUp 方法来结束 我不能并且不想修改每个地方 所以顺序是这样的 Connection con connect
  • Java 中 .NET 的 Lambda 表达式

    我最近 再次 从 C 迁移到 Java 但我非常怀念 lambda 表达式和 C 的 IEnumerable Foreach 之类的东西 所以我正在寻找Java中的lambda表达式库 有比这更好的图书馆吗LambdaJ http code

随机推荐

  • 测试文件是否已下载 Selenium/C# (Google Chrome)

    我想单击下载文件的按钮on click 并测试是否已下载所需的文件 我已经用 google 搜索过这个问题 但不幸的是没有找到关于这个主题的任何具体答案 我发现的很多帖子都已经过时了 2014 年 我敢打赌 Selenium 现在肯定已经改
  • WSO2 API 管理器,无效。无法找到请求目标的有效认证路径

    我已经在本地启动了 WSO2 API Manager 我正在尝试添加 API 端点https联系 它向我展示了这种错误 它向我展示了Invalid unable to find valid certification path to req
  • C# 与 Excel 中的模数有何不同?

    我正在试验负基数系统 并使用 Excel 来处理和检查我的计算 我注意到 C 与 Excel 之间存在差异 为什么 C 返回的结果与 Excel 不同 例如 C 146 3 2 Excel mod 146 3 1 假设我们有四个整数 x y
  • string.replace(fromCharCode() , '') 无法替换字符

    当我解析 XML 时 它包含异常的十六进制字符 所以我尝试用空白来代替它 但这根本不起作用 原人物 hex code 253 255 code xmlData String replace String fromCharCode 253 2
  • 查找矩阵内的最大和子=矩形[重复]

    这个问题在这里已经有答案了 可能的重复 获取总和最大的子矩阵 https stackoverflow com questions 2643908 getting the submatrix with maximum sum 给定一个正整数和
  • 如何根据不同的URL参数和请求值写入不同的数据库?

    我正在尝试创建一个 REST API 它选择要写入的适当的 mongo 数据库以及正确的集合 如何选择与参数同名的数据库以及集合 即将推出的 v0 6 Eve 将原生支持多个 Mongo 实例 新功能 支持多个 MongoDB 数据库和 或
  • 如何在 Mac OS 上使用 homebrew 将 postgresql 从 10.1 降级到 9.6 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我的 Mac 上装有 postgresql 10 1 我的工作网站需要 9 6 才能在本地计算机上运行 找不到有关如何卸载或降级到 9 6
  • 如何解决此错误 (GWT)

    运行我的应用程序后出现此错误 编译过程中没有出现错误 另外 没有其他应用程序在运行 在端口 8888 警告 上启动 Jetty 失败 电子邮件受保护 cdn cgi l email protection 8888 java net Bind
  • 如何在java中为游戏实现双缓冲?

    因此 在我正在开发的游戏中 我有一个弹珠跟随鼠标 但当它这样做时 屏幕会闪烁 背景包括两个 jpeg 和 9 个矩形 我该如何进行双缓冲呢 这是主窗口的代码 Write a description of class Window here
  • R:分割数字字符串

    我正在尝试拆分 40 位数字的数字字符串 即拆分123456789123456789123456789 into 1 2 3 4 etc 很遗憾strsplit不起作用 因为它需要字符 并使用转换字符串as character不起作用 因为
  • Zappa/AWS - 电子邮件不会发送并且只是超时

    目前 我已经为我的交易电子邮件提供商 Postmark 尝试了普通的 Django SMTP 和一些不同的基于 api 的 Django 库 当我运行我的开发服务器时 一切都运行良好 通过 Postmark API 发送电子邮件没有任何问题
  • Get-ADPrincipalGroupMembership -Identity 不接受变量

    在几个不同的域中工作 这些域具有不同的命名模式 因此 我正在编写一个进入每个域的脚本 并检查它们的组成员身份 该脚本所做的第一件事是询问用户的姓氏 然后我用Get ADUser选择samaccountname并将其绑定到一个变量 samac
  • .NET 相当于 Java 资源包中的选择吗?

    在Java资源包中 我可能有以下资源包定义 en GB 英式英语 jobs search resultstr There 1 choice 0 are no jobs 1 is one job 1
  • 当有人点击特定链接时如何显示加载对话框?

    我确实有一个 URL 可以打开一个加载速度非常慢的网页 而且我无法控制它 我确实想在有人单击此 URL 时显示加载对话框 或者在发生这种情况时使用覆盖 div 阻止页面 注意 这与 ajax 相关的问题不是同一个问题 这是针对用户的正常 U
  • 如何在artifactory中配置更长的版本号

    我们的 jar 的版本号必须比 x x x 更长 我们宁愿需要 x x x x 来集成一些老式的自制机制 这是因为我们用 x x x 标记我们的软件 一旦我们交付给客户 就必须在此时准确地构建一个特定的 jar 以适应另一个后端 它与我们的
  • 无法将 SCSS 变量设置为 CSS 变量?

    考虑以下 SCSS color black 000000 body color color black 当用node sass编译时版本4 7 2 它会生成以下 CSS body color 000000 当我编译相同版本的SCSS时4 8
  • 如何加密用户数据,以便只有他们才能解密?

    我正在考虑创建一个 Web 应用程序 让人们输入文本 使用 SSL 连接 并且在保存到数据库之前将其加密 目标是只有用户才能解密它 您可以让用户输入密钥及其数据 并在他们想要查看数据时再次输入 而不是存储密钥 但这对用户来说会有点痛苦 但是
  • 32 位程序可以在 64 位操作系统上使用超过 4GB 的内存吗?

    在 64 位操作系统上运行的 32 位程序是否能够使用超过 4GB 的内存 如果可用 简短的回答是 是的 更长的答案取决于 硬件支持页面重新映射 这基本上为您的程序提供了一个将几个页面的窗口放入更大的内存区域的窗口 然而 该窗口应该由程序本
  • Azure 中的 SignalR 横向扩展适用于高频场景

    根据我对 Azure 中 SignalR 横向扩展的阅读 推荐的方法是使用 Azure ServiceBus 作为背板 但同时使用背板进行高频消息传递也存在限制 就限制章节而言SignalR 中的横向扩展 http www asp net
  • 了解 Java 中同步块与易失性变量的原子性、可见性和重新排序

    我试图理解volatile Java 并发实践 一书中的关键字 我比较synchronized关键字与volatile变量在三个方面 原子性 波动性和重新排序 我对此也有一些疑问 我在下面一一讨论过 1 可见性 同步 与 易变 书上说以下关