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

使用volatile和同步时,刷新或发布到各个线程的内存范围是什么?

费秦迟
2023-03-14
问题内容

这个问题仅涉及内存可见性,而不是发生在之前和之后。Java中有四种方法可以保证一个线程中的内存更改对另一线程可见。(参考http://gee.cs.oswego.edu/dl/cpj/jmm.html)

  1. 写入线程释放同步锁,而读取线程随后获取该相同的同步锁。
  2. 如果将一个字段声明为易失性字段,则在写入线程执行任何进一步的内存操作之前,写入该线程的任何值都会被写入线程并使写入线程可见(即,出于手头的目的,将立即刷新该字段)。
  3. 线程第一次访问对象的字段时,它将看到该字段的初始值或自其他线程写入以来的值。
  4. 线程终止时,所有写入的变量都将刷新到主内存。

根据Java Concurrency in Practice,有关此类问题的圣经:

易失性变量的可见性影响超出了易失性变量本身的值。当线程 A 写入易失性变量,随后线程 B 读取相同的变量时,在写入易失性变量之前 A 可见的
所有 变量的值在读入volatile变量后对 B 可见。

易失性问题

这是否意味着JVM实际上跟踪volatile变量的读取和写入,以便知道如何刷新内存从 一个 ,而不是 一个ç ?因此, A
写入变量,后来 C 从变量中读取,然后 B 从变量中读取,则刷新是在 ABAC 之间的每个线程基础上完成的,但
不是 BC ?或者,这是否意味着所有高速缓存的内存都已刷新,而与线程无关?仅清除volatile变量,还是清除所有缓存的内存?

同步问题

对于synchronized关键字刷新,它说只有保证在锁内更新的内存才能发布到其他线程。这意味着在下面的代码中,两个正在运行的线程method()(离开同步块)将刷新staticVar2到另一个线程,但
不是 staticVar1正确吗?

另外,在中method2()differentLock如果另一个线程正在执行,则同步可能会导致先发生后发生问题method()。但是,问题在于可见性。如果执行线程
Amethod,则稍后执行线程 B ,即使两个线程未在同一锁上同步method2()staticVar2发布的值还是从 A
B 的值?

static int staticVar1, staticVar2;
void method() {
    staticVar1++;
    synchronized (lock) {
        staticVar2++;
    }
}
void method2() {
    synchronized (differentLock) {
        staticVar2++;
    }
}

静态问题

在我看来,如果staticVar1从不更新到其他线程,那么任何程序中的所有静态变量都需要volatile声明,或者只能以synchronized块形式访问。这似乎很严厉,但这是正确的吗?我肯定在我的时间里看到了很多静态变量,它们是不同步的。

综上所述

  1. 易失性读写会将所有内存刷新到所有线程,还是仅在两个访问线程之间?不管是哪个答案,所有内存都是刷新的还是仅是可变变量?
  2. 退出同步块时,是否会清除所有已更改的内存,或者仅清除该块内已更改的内存?如果不是所有的内存都被刷新,线程同步过的锁对象是否必须相同才能看到该值(即,锁对象是否对内存可见性有影响)?
  3. 是否必须同步两个线程访问的所有静态变量?

问题答案:

就内存而言,没有范围限制。当您具有读取或写入障碍时,它将应用于所有内存读取/写入。

我看到的限制是内存映射。当您对文件进行内存映射时,必须小心如何将其提供给另一个线程使用,因为这个新的内存映射在另一个线程中可能不可见,从而立即导致BUS错误(并导致JVM崩溃)。
OS漏洞(作为Linux和Windows的最新版本)似乎没有此问题。

这意味着在下面的代码中,两个运行method()的线程离开同步块将把staticVar2刷新到另一个线程,而不是staticVar1,对吗?

可能会更早地在staticVar2时刷新statixVar1。无法保证时间,但是可以保证订购。

如果线程A执行方法,则稍后线程B执行method2(),即使两个线程不在同一锁上同步,staticVar2的值是否也从A发布到B?

是的,所使用的锁与事前保证无关紧要。

易失性读写会将所有内存刷新到所有线程,还是仅在两个访问线程之间?不管是哪个答案,所有内存都是刷新的还是仅是可变变量?

所有脏内存都在写屏障上被刷新,所有读将在读屏障上保持顺序一致。 volatile同时执行写屏障和读屏障。

退出同步块时,是否会清除所有已更改的内存,或者仅清除该块内已更改的内存?

该线程更改了所有内存。

是否必须同步两个线程访问的所有静态变量?

仅当一个线程修改了变量时。任何数量的线程都可以读取静态值而无需同步。



 类似资料:
  • 这个问题只涉及内存可见性,而不是发生在之前和之后。Java中有四种方法可以保证一个线程中的内存更改对另一个线程可见。(参考http://gee.cs.oswego.edu/dl/cpj/jmm.html) 写入线程释放同步锁,读取线程随后获取相同的同步锁 根据Java Concurrency in Practice的说法,《圣经》讨论了这样的问题: 可变变量的可见性影响超出了可变变量本身的值。当线

  • 问题内容: 我知道Java中的易失性变量的目的是使对此类变量的写入对其他线程立即可见。我还知道,同步块的作用之一是将线程本地内存刷新到全局内存。 在这种情况下,我从未完全理解对“线程本地”内存的引用。我了解仅存在于堆栈中的数据是线程局部的,但是当谈论堆上的对象时,我的理解变得模糊。 我希望能就以下几点发表评论: 在具有多个处理器的计算机上执行时,刷新线程本地内存是否仅是指将CPU缓存刷新到RAM中

  • Java类: 应用yml公司 应用程序模拟ecom。yml公司 当我击中时,http://localhost:8080/hello,我得到的回应是“Hello mock api.com!”。 如果我从应用程序中删除模拟的ecom。然后调用刷新后api调用http://localhost:8080/refresh要刷新上下文,我希望得到“Hello dev api.com!”但我收到了“你好,moc

  • 问题内容: 线程1:正在执行此循环 线程2将运行错误设置为假如果运行是易失性变量,则线程1退出循环并显示“完成”。 我的问题是,如果运行不是易失的,那么Thread1何时从主内存中读取运行变量? 注意:我很了解同步和volatile变量之间的关系,但是即使运行不是volatile或同步的,线程1也会停止。所以我的问题是,鉴于没有同步或没有波动,线程1什么时候决定从主存储器读取数据 问题答案: 这在

  • 问题内容: 知道 对于声明为volatile的所有变量,读写是原子的 问题1: 这是否可以理解为 操作是原子的吗? 然后 将变量标记为volatile并不能消除所有同步原子操作的需要,因为仍然可能发生内存一致性错误。 问题2: 我想知道在什么情况下(如果有的话)有可能看到一个已标记的变量,而看不到任何标记为已同步的块的方法(试图访问/修改该变量)? 换句话说,是否需要标记所有需要防止并发修改的变量

  • OpenGL和Vulkan都允许通过分别使用和来获取指向部分GPU内存的指针。它们都为映射的内存提供了。要将其内容解释为一些数据,必须将其转换为适当的类型。最简单的例子可以是转换为以将内存解释为浮点数或向量或类似数组。 似乎任何类型的内存映射在C中都是未定义的行为,因为它没有内存映射的概念。但是,这并不是真正的问题,因为这个主题超出了C标准的范围。但是,仍然存在的问题。 在链接问题中,指针被额外标