当前位置: 首页 > 知识库问答 >
问题:

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

蔡明贤
2023-03-14

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

  1. 写入线程释放同步锁,读取线程随后获取相同的同步锁

根据Java Concurrency in Practice的说法,《圣经》讨论了这样的问题:

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

这是否意味着JVM实际上会跟踪易失性变量的读写,以便知道如何将内存从A刷新到B,而不是从A刷新到C?所以A向变量写入数据,然后C从变量中读取数据,然后B从变量中读取数据,刷新是在A和B以及A和C之间按线程进行的,而不是B和C?或者,这是否意味着不管线程如何,所有缓存的内存都会被刷新?是只刷新易失性变量,还是所有缓存内存?

对于同步的关键字刷新,它说只有在锁内部更新的内存才保证发布到其他线程,那就暗示在下面的代码中,两个线程运行method(),离开同步的块将刷新staticVar2到另一个线程,而不是staticVar1,是这样吗?

此外,在method2()中,如果另一个线程正在执行method(),则通过differentLock进行同步可能会导致“先发生后发生”问题。然而,问题在于可见度。如果线程A执行method,那么后面的线程B执行method2(),那么staticVar2的值是否从A发布到B,即使两个线程没有在同一个锁上同步?

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

在我看来,如果staticVar1从未更新到其他线程,那么任何程序中的所有静态变量都需要易失性声明,或者只能在同步的块中访问。这似乎相当苛刻,但这是正确的吗?我在我的时代确实见过很多不同步的静态变量。

  1. 易失性读写是将所有内存刷新到所有线程,还是仅在两个访问线程之间?无论答案是哪一个,是所有内存都被刷新了,还是只有易失性变量

共有1个答案

邵伟
2023-03-14

内存方面没有范围限制。当您有读或写障碍时,它适用于所有内存读/写。

我看到的一个限制是内存映射。当你对一个文件进行内存映射时,你必须小心如何使它对其他线程可用,因为这个新的内存映射可能在另一个线程中不可见,从而立即导致总线错误(以及JVM崩溃)。这似乎是一个操作系统错误,因为最新版本的Linux和Windows似乎没有这个问题。

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

statixVar1将始终在StatiVar2运行时刷新,可能更快。没有时间保证,但订单是有保证的。

如果线程A执行方法,那么后面的线程B执行方法2(),是从A到B发布的staticVar2的值,即使两个线程没有在同一个锁上同步?

是的,所用的锁对保证之前发生的事情并不重要。

易失性读写是将所有内存刷新到所有线程,还是仅在两个访问线程之间?无论答案是什么,是将所有内存刷新还是仅刷新易失性变量?

所有脏内存都在写屏障上刷新,所有读取都在读屏障上保持一致的顺序。<代码>易失性在写和读上执行写屏障。

退出同步块时,是否刷新所有更改的内存,还是仅刷新块内更改的内存?

所有的内存都被那个线程改变了。

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

只有当一个线程修改变量时。任何数量的线程都可以在没有同步的情况下读取静态值。

 类似资料:
  • 问题内容: 这个问题仅涉及内存可见性,而不是发生在之前和之后。Java中有四种方法可以保证一个线程中的内存更改对另一线程可见。(参考http://gee.cs.oswego.edu/dl/cpj/jmm.html) 写入线程释放同步锁,而读取线程随后获取该相同的同步锁。 如果将一个字段声明为易失性字段,则在写入线程执行任何进一步的内存操作之前,写入该线程的任何值都会被写入线程并使写入线程可见(即,

  • 最近我在读一些关于java并发的书。关于线程安全,如果不可能使一个类变为inmutable,那么可以通过同步它的数据来确保线程安全。 下面的类显然不是线程安全的 然后我可以同步写,但它不会保持线程安全 因为我不仅需要同步写入,还需要同步读取 现在的问题是,通过使用易失性,我可以保证其他线程会看到更新的值,所以这让我认为这个类应该是线程安全的 最后一个类线程安全吗??

  • 运行之后(在jdk1.8中),答案不是1000。请告诉我原因。

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

  • 官方记录说 写入易失性字段与监视器释放具有相同的记忆效果,从易失性字段读取与监视器获取具有相同的记忆效果。 和 有效地,挥发性的语义学得到了实质性的加强,几乎达到了同步的水平。为了可见性的目的,挥发性字段的每次读取或写入都像“半”次同步。 从这里开始。 这是否意味着,对volatile变量的任何写入都会使执行线程将其缓存刷新到主存中,而每次从volatile字段读取都会使线程从主存重新读取其变量?

  • 在《有效Java》一书中: 后台线程不会在一秒钟后停止。因为提升,在JVM中优化,HotSpot服务器VM做。 您可以在以下主题中查看这一点: 为什么HotSpot会使用提升优化以下内容?。 优化过程如下: 有两种方法可以解决这个问题。 volatile的函数是 -禁止提升 -它保证任何读取该字段的线程都会看到最近写入的值 上面的代码在有效Java书中是正确的,它相当于使用来装饰。 如果此方法忽略