java中load,关于java:LoadLoad屏障实际上是做什么的?

在Java中,当我们有两个线程共享以下变量时:

int a;

volatile int b;

如果线程1做到了:

a = 5;

b = 6;

然后在这两个指令之间插入一个StoreStore屏障,并且将" a"刷新回主存储器。

现在,如果线程2做到了:

if(b == 6)

a++;

在两者之间插入了LoadLoad障碍,我们保证,如果新值" b"可见,那么新值" a"也可见。 但是实际上是如何实现的呢? LoadLoad是否会使CPU缓存/寄存器无效? 还是只是指示CPU重新从CPU中读取从volatile中读取的变量的值?

我已经找到有关LoadLoad barrier的以下信息(http://gee.cs.oswego.edu/dl/jmm/cookbook.html):

LoadLoad Barriers The sequence: Load1; LoadLoad; Load2 ensures that

Load1's data are loaded before data accessed by Load2 and all

subsequent load instructions are loaded. In general, explicit LoadLoad

barriers are needed on processors that perform speculative loads

and/or out-of-order processing in which waiting load instructions can

bypass waiting stores. On processors that guarantee to always preserve

load ordering, the barriers amount to no-ops.

但这并不能真正解释这是如何实现的。

答案取决于处理器体系结构-同一文档中有一个表,其中每个处理器指令均显示LoadLoad是x86上的空操作。

那它怎么运作的呢?我的意思是,在StoreStore之后,值将刷新回内存中。但是,线程2应该如何看待它们呢?如果该LoadLoad评估为no-op,则线程2可以继续使用缓存的值。

因为处理器的内存模型足够强大,因此可以保证确实如此。林试图说的是,Java承诺,如果您使用volatile,将/将不会发生某些事情。如何在JVM中实现此功能是特定于处理器的,并且使用临时指令(如果相关,则不使用任何指令)。您可以在此处了解有关LoadLoad / x86点的更多信息:altair.cs.oswego.edu/pipermail/concurrency-interest/2012-July/

您可以阅读有关LoadLoad并非空当的CPU体系结构(例如ARM)的更多信息。似乎是沉重的东西:)

我将举例说明如何实现这一目标。您可以在此处阅读更多详细信息。如前所述,对于x86处理器,LoadLoad最终变为无操作。在我链接的文章中,马克指出

Doug lists the StoreStore, LoadLoad and LoadStore

因此,本质上,唯一需要的障碍是用于x86体系结构的StoreLoad。那么如何从低水平实现呢?

这是博客的摘录:

这是它为易失性和非易失性读取生成的代码:

nop                       ;*synchronization entry

mov    0x10(%rsi),%rax    ;*getfield x

对于易失性写入:

xchg   %ax,%ax

movq   $0xab,0x10(%rbx)

lock addl $0x0,(%rsp)     ;*putfield x

lock指令是Doug的食谱中列出的StoreLoad。但是,锁定指令还会将所有读取与其他进程同步,如所列

Locked instructions can be used to synchronize data written by one

processor and read by another processor.

这减少了必须为易失性负载发出LoadLoad LoadStore屏障的开销。

话虽如此,我将重申亚述指出的内容。对于开发人员来说,发生的方式并不重要(如果您对处理器/编译器实现程序感兴趣的话,则另当别论)。 volatile关键字是一种界面说法

您将获得由另一个线程编写的最新读物

您将不会因JIT编译器优化而烦恼。

好的链接。我会悄悄地改写一下:"您将获得由另一个线程编写的最新读取信息" =>"随后从易失性变量读取内容时,您最终将看到写入内容-"最终"实际上几乎立即就意味着含义";- )

实际上,重要的是,如果您对应用程序运行哪种硬件最快或如何获得最高性能感兴趣。我们希望从四插槽Xeon(64 SMT)中受益,远比我们最终受益。如果您无法控制硬件或仅在单个套接字上运行,那可能就不成问题了,但是并发实现的详细信息以及它们如何影响大型计算机的可伸缩性,如果早日知道,肯定会影响设计。

@RalfH我使用volatile关键字代表普通开发人员发言。一般来说,开发人员无需担心易失性的实现方式。当您知道基础架构改变了您如何以不同方式使用volatile时,您是否看到过实例?

:)不,因为我也不知道硬件的工作方式,所以我宁愿进行性能分析。这就是我注意到类似ConcurrentHashMap的volatile获取性能不好的原因,因此,一旦它们的内容稳定,我们最终将它们替换为CopyOnWriteHashMaps。如果您想知道即将发生的事情,那么硬件的详细信息就在测试中。就像我想知道的那样,Haswell中的硬件事务存储对Java并发意味着什么。

好吧,那令人费解:)我不确定我的理解是否正确:由于x86上的LoadLoad障碍是无操作的,因此Marcs程序生成了StoreLoad障碍? (以" lock"开头的行)。如果易失性读产生了一条额外的指令(锁),为什么他说我们可以期望易失性读是免费的?回到我最初的问题,如果我们在读完一个volatile之后在Marcs示例中添加了一个对非易失性的读取,那么"锁定"指令是否会发挥作用(确保非易失性的可见性)?

@Janek如果您读得更多,他会提到It appears as though reads to volatile variables are not free in Java on x86, or at least on the tested setup.并且StoreLoad是通过写入易失性变量而不是读取生成的。与非易失性负载相比,非易失性负载增加了25%,这是因为x86缓存的一致性。

@Jarek回答您的其他问题。 (ensure visibility of a non-volatile)仅当您对volatile字段进行写操作时。否则就不会发生事前关系,因此您无需担心可见性。如果确实这样做了,则lock指令似乎可以保证可见性。我正在基于data written by one processor and read by another processor做出该断言

"我写了一个很小的玩具程序,它循环访问了一个volatile变量"-认为访问意味着读。可惜他没有附上消息来源。因此,最重要的是,在写入volatile时插入的StoreLoad屏障完成了其他处理器在该写入之前查看内存更改所需的所有工作。然后,易失性读取与非易失性读取完全相同(在asm指令方面)。为了弄清楚这个StoreLoad屏障如何将内存更改推向其他处理器,我应该研究锁指令,也许还要研究xchg?

lock instruction and maybe xchg是,还有缓存一致性协议:en.wikipedia.org/wiki/Cache_coherence

If that LoadLoad evaluates to no-op then thread 2 can continue using cached values.

食谱中的"可以订购"表对此进行了说明。

编程顺序为

read b

read a

write a

"缓存一个",表示代码已重新排序

read a

...

read b

禁止重新排序。

我实际上是指在CPU缓存中进行真正的缓存,而不是对指令进行重新排序。

负载是负载,它将不会从CPU寄存器中读取。

@zhong我认为Janeks担心的是,如果一个域在另一个处理器写操作后从未初始化加载,那么该域如何在处理器寄存器中保持最新状态。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`java.lang.IllegalStateException: Failed to load ApplicationContext`表示在加载应用程序上下文(ApplicationContext)时发生了错误。这通常是由于配置问题或依赖项缺失引起的。 `ApplicationContext`是Spring框架的核心接口,它负责管理和组织应用程序的组件、配置和依赖项。当应用程序启动时,Spring会尝试加载和初始化这个上下文,以便能够正确地创建和管理应用程序的组件。 当出现`Failed to load ApplicationContext`异常时,可能有以下几个原因: 1. 配置错误:应用程序的配置文件(如XML配置文件或注解配置)存在错误,导致Spring无法正确加载应用程序上下文。检查配置文件是否存在语法错误或配置项是否正确。 2. 依赖项缺失:应用程序可能依赖于其他模块或库,但这些依赖项未被正确地引入到项目。检查项目的依赖项配置,确保所有需要的库都正确添加到项目。 3. 资源加载失败:应用程序可能依赖于外部资源(如数据库连接、文件等),但无法正确加载这些资源。检查资源的配置是否正确,并确保资源可用。 要解决这个问题,你可以按照以下步骤进行排查: 1. 检查日志:查看完整的异常堆栈跟踪和错误信息,以了解导致异常的具体原因。 2. 检查配置文件:确保配置文件的语法没有错误,并且配置项与实际情况匹配。 3. 检查依赖项:检查项目的依赖项配置,确保所有需要的库都正确添加到项目,并且版本号与实际使用的一致。 4. 检查资源:如果应用程序依赖于外部资源,例如数据库连接或文件,确保这些资源可用并且配置正确。 通过逐步排查这些可能的原因,你应该能够找到并解决`Failed to load ApplicationContext`异常。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值