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

Java易失性变量是否在读取之前强加了“事前发生”关系?

居琛
2023-03-14
问题内容

我有一段代码看起来像这样:

片段A:

class Creature {
    private static long numCreated;
    public Creature() {
        synchronized (Creature.class) {
            numCreated++;
        }
    }
    public static long numCreated() {
        return numCreated;
    }
}

根据我的理解,由于的读取numCreated不同步,因此如果线程A Creature在下午1点创建了一个,而线程B
numCreated()在下午2点进行了读取,numCreated()则很可能返回0或1(即使线程A在1.05 pm完成了对对象的初始化) )。

所以我添加synchronizednumCreated()

片段B:

class Creature {
    private static long numCreated;
    public Creature() {
        synchronized (Creature.class) {
            numCreated++;
        }
    }
    public static synchronized long numCreated() { // add "synchronized"
        return numCreated;
    }
}

一切都很好,除了我在想,如果我将其修改为 Snippet C ,变量是否numCreated仍正确同步?

片段C:

class Creature {
    private static volatile long numCreated; // add "volatile"
    public Creature() {
        synchronized (Creature.class) {
            numCreated++;
        }
    }
    public static long numCreated() { // remove "synchronized"
        return numCreated;
    }
}

使用 代码片段C ,是否可以保证线程A在下午1:05完成对象创建之后,线程B的调用numCreated()一定会返回1

PS:我了解在实际情况下,我可能会使用an,AtomicLong但这是出于学习目的


问题答案:

请参阅http://download.oracle.com/javase/6/docs/api/java/util/concurrent/package-
summary.html#MemoryVisibility

每次对同一字段进行后续读取之前,都会写入易失字段。易失性字段的写入和读取与进入和退出监视器具有相似的内存一致性效果,但是不需要互斥锁定。

所以答案是肯定的。在构造函数中写入volatile发生在读取volatile中numCreated()。并且由于非原子增量仍在同步块中完成,因此同步是可以的(增量不是原子增量,但对volatile
long的写入是正确的)。



 类似资料:
  • 问题内容: 我尝试了解为什么此示例是正确同步的程序: 由于存在冲突的访问(存在对a的写入和读取),因此在每个顺序一致性中,必须在访问之间的关系之前执行。假设顺序执行之一: 是1发生-在2之前发生,为什么? 问题答案: 不,在相同变量的易失性写入之前(以同步顺序),在易失性写入 之前 不一定 会发生 易失性读取。 这意味着它们可能处于“数据争用”中,因为它们“冲突的访问未按先发生后关系进行排序”。如

  • 我想澄清发生前关系是如何与不稳定变量一起工作的。让我们有以下变量: 和线程A: 和线程B: 根据Java内存模型(JMM),以下语句是否正确?如果不是,正确的解释是什么? 总是发生-之前 在JMM中发生在之前,只有当它实际发生在时间之前 在JMM中发生在之前(并且将被可预测地分配)如果实际发生在

  • 教程http://tutorials.jenkov.com/java-concurrency/volatile.html说 如果读取/写入最初发生在对易失性变量的写入之前,则不能将从其他变量的读取和写入重新排序为在对易失性变量的写入之后发生。写入挥发性变量之前的读取/写入保证在写入挥发性变量之前“发生”。 什么是“写入挥发性变量之前”?这是否意味着以前的读/写在相同的方法中,我们正在写入易失性变量

  • 问题内容: 我想说明 先发生的 关系如何与 volatile 变量一起使用。让我们有以下变量: 和线程A: 和线程B: 根据Java内存模型(JMM),以下语句正确吗? 如果没有,正确的解释是什么? 总是在 发生之前 __仅在JMM中实际发生时才 发生- 在JMM中 __ 如果实际上发生在时间之前,则发生在JMM中-before -before (并且将可预测地分配) 否则,和之间的顺序不确定,并

  • 问题内容: 我有两个线程: 线程数:1 线程数:2 在这里,a和b被声明为volatile。我不了解如何在a = 1之间创建“先发生”边;y = a; 在x = b之间; 并且b = 1; 我知道通过使用volatile变量可以防止从线程缓存中读取过时的值。但是,可变变量如何才能确保在订购前发生。 具体来说,我不明白这一点: 后续每次读取同一字段之前,都会对易失字段进行写操作。 e头有效吗? 问题

  • 我对线程的概念还是相当陌生的,并试图对它有更多的了解。最近,我看到Jeremy Manson写的一篇关于Volatile在Java中的含义的博文,他写道: 当一个线程写入一个易失性变量,而另一个线程看到该写操作时,第一个线程将告诉第二个线程内存中的所有内容,直到它执行了对该易失性变量的写操作为止。[...] 线程1在写入之前看到的所有内存内容,在读取的值之后,必须对线程2可见。[我自己加的重点]