当前位置: 首页 > 面试题库 >

Java同步的内存影响

皇甫树
2023-03-14
问题内容

JSR-133常见问题解答说:

但是同步不仅仅是相互排斥。同步确保以可预见的方式使线程在同步块之前或期间对内存的写入对于在同一监视器上同步的其他线程可见。退出同步块后,我们释放监视器,其作用是将缓存刷新到主内存,以便该线程进行的写入对于其他线程可见。在进入同步块之前,我们需要获取监视器,该监视器具有使本地处理器缓存无效的作用,以便可以从主内存中重新加载变量。然后,我们将能够看到以前版本中所有可见的写入。

我还记得读过有关在现代Sun VM上进行无竞争的同步很便宜的信息。我对此说法有些困惑。考虑如下html" target="_blank">代码:

class Foo {
    int x = 1;
    int y = 1;
    ..
    synchronized (aLock) {
        x = x + 1;
    }
}

对x的更新需要同步,但是获取锁是否也从缓存中清除y的值?我无法想象是这种情况,因为如果这是真的,锁条之类的技术可能无济于事。或者,JVM是否可以可靠地分析代码以确保不使用相同的锁在另一个同步块中修改y,从而在进入同步块时不将y的值转储到高速缓存中?


问题答案:

简而言之,就是 JSR-133的解释太过分了
。这不是一个严重的问题,因为JSR-133是非规范性文档,不属于语言或JVM标准。而是,只有文档解释了一种可能的策略,该策略 足以
实现内存模型,但通常不是 必需的
。最重要的是,有关“缓存刷新”的评论基本上完全不合时宜,因为实质上零的体系结构可以通过执行任何类型的“缓存刷新”来实现Java内存模型(许多体系甚至没有这样的指令)。


Java内存模型是根据可见性,原子性,发生关系之前的事物等形式正式定义的,它使用精确(数学上)定义的方法,确切地解释了哪些线程 必须
看到什么,在其他操作和其他关系之前 必须 执行哪些操作。模型。未正式定义的行为可能是随机的,也可能是在某些硬件和JVM实现上的实践中明确定义的行为-
但是您当然不应该依赖它,因为将来它可能会发生变化,并且您永远无法真正确定除非您编写了JVM并且对硬件语义了如指掌,否则首先要对它进行明确定义。

因此,您引用的文本不是正式描述Java保证的内容,而是描述某种具有非常弱的内存顺序和可见性保证的假设体系结构如何使用缓存刷新
满足Java内存模型要求。显然,关于缓存刷新,主内存等的任何实际讨论通常都不适用于Java,因为这些概念在抽象语言和内存模型规范中不存在。

在实践中,内存模型提供的保证要比完全刷新弱得多-
每次原子,并发相关或锁定操作刷新整个高速缓存都将是非常昂贵的,并且在实践中几乎从未做到过。而是使用特殊的原子CPU操作,有时与内存屏障指令结合使用,这有助于确保内存可见性和顺序。因此,通过注意到第一个为true而第二个为非,廉价的无竞争的同步与“完全刷新缓存”之间的明显不一致得到了解决-
Java内存模型不需要完全刷新(实际上没有刷新发生)。

如果正式记忆模型过于繁琐而无法消化(您不会孤单),您还可以通过阅读Doug
Lea的菜谱深入研究该主题,该菜谱实际上与JSR-133常见问题解答相关,但这是从具体的硬件角度出发的问题,因为它是针对编译器作者的。在这里,他们确切地讨论了特定操作(包括同步)所需的障碍,并且在那里讨论的障碍可以很容易地映射到实际硬件。食谱中讨论了许多实际映射。



 类似资料:
  • 9.4. 内存同步 你可能比较纠结为什么Balance方法需要用到互斥条件,无论是基于channel还是基于互斥量。毕竟和存款不一样,它只由一个简单的操作组成,所以不会碰到其它goroutine在其执行"期间"执行其它的逻辑的风险。这里使用mutex有两方面考虑。第一Balance不会在其它操作比如Withdraw“中间”执行。第二(更重要)的是"同步"不仅仅是一堆goroutine执行顺序的问题

  • 我想知道如何增加IntelliJIDEA用于同步项目的Gradle Daemon进程的堆大小? 当前流程使用-Xms256m -Xmx512m 我已经换了包装纸。属性文件到:

  • 请看下面给我带来麻烦的方法: 然后是run方法:

  • 在阅读artemis时,docs理解-artemis在内存中存储整个当前活动消息,并可以根据设置将消息卸载到给定队列/主题的分页区域&artemis日志只追加。 关于这一点 代理如何以及何时从日记同步消息(仅在重新启动期间?) 它如何标识要从日记中删除的消息(例如:如果日记是仅追加模式,如果持久消息的使用者访问消息,那么代理如何从日记中删除一条消息而不保留索引)。 将每个活动消息保存在内存中,甚至

  • 问题内容: 我有一个Web应用程序,人们需要资源。使用同步哈希映射来缓存此资源以提高效率。这里的问题是,当两个不同的请求同时到达同一未缓存资源时:检索资源的操作占用大量内存,因此我想避免为同一资源多次调用它。 有人可以告诉我以下代码段是否存在任何潜在问题吗?提前致谢。 问题答案: 一个可能的问题是,您通过在一个块内执行来创建不必要的竞争,因此许多线程无法同时检索其(独立)资源。这可以通过使用map

  • 跟进这个问题(Java线程安全-多原子操作?),我不想再增加更多的问题,但现在我有一个疑问: 应该是这样的: 为了保证线程安全。对吗? 所以操作是原子的,但将它们组合起来需要同步,对吗?在这一点上,只使用简单的 HashMap 而不是并发 HashMap 是否有意义,因为我们手动处理同步? CHM中是否有任何方法可以原子地使其工作?