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

Java易失性重排序防止范围

蒙化
2023-03-14

对易失性字段的写和读分别防止了在易失性字段之前和之后的读/写的重新排序。在写到易失性变量之前的变量读/写不能被重新排序为在它之后发生,在从易失性变量读到之后的读/写不能被重新排序为在它之前发生。但是这种禁止的范围是什么呢?正如我所理解的,volatile变量只能在使用它的块内防止重新排序,对吗?

为了清楚起见,让我举一个具体的例子。假设我们有这样的代码:

int i,j,k;
volatile int l;
boolean flag = true;

void someMethod() {
    int i = 1;
    if (flag) {
        j = 2;
    }
    if (flag) {
        k = 3;
        l = 4;
    }
}

让我再举一个具体的例子来说明范围以澄清事情:

setVolatile() {
   l = 5;
} 

callTheSet() {
   i = 6;
   setVolatile();
}

在这种情况下,编译器会禁止重新排序iwrite吗?或者编译器不能/没有被编程来跟踪其他方法在volatile情况下发生的事情,并且iwrite可以被重新排序为在setvolatile()之前发生?或者编译器根本不重新排序方法调用?

我的意思是,一定有一个点,当编译器将无法跟踪一些代码是否应该发生在一些易失性字段写入之前。否则,一个易失性字段写/读可能会影响一半程序的排序,如果不是更多的话。这是一个罕见的病例,但这是可能的。

共有1个答案

贺雅健
2023-03-14

显然,写到l会阻止写到k的重新排序,但它会阻止写到i和J的重新排序吗?

你说的重新排序是什么意思并不完全清楚;见我上面的评论。

但是,在Java5+内存模型中,我们可以说,在写到L之前发生的写到IJ对于另一个线程在读取L...之后是可见的,前提是在写到L之后没有写到IJ

这确实会限制写入IJ指令的任何重新排序。具体地说,不能将它们移到写到L之后的内存写屏障之后,因为这可能导致它们对第二个线程不可见。

但是这种禁止的范围是什么呢?

本身没有禁令。

在每个线程t执行的所有线程间操作中,t的程序顺序是一个总顺序,它反映了根据t的线程内语义执行这些操作的顺序。

如果所有动作都以与程序顺序一致的总顺序(执行顺序)发生,那么一组动作是顺序一致的,而且,变量v的每次读r看到写w到v所写的值,这样:

>

  • w在执行顺序中位于r之前,并且

    注意,在这个定义中没有提到块或作用域。

  •  类似资料:
    • a)为什么除了“00”之外还有其他输出? b)如何修改代码以便始终打印“00”。 对于a)我的回答是:在没有任何volatile/同步构造的情况下,编译器可以重新排序一些指令。特别是“this.initialint=val;”和“this.flag=true;”可以切换,这样就可以发生这种情况:线程都启动了,t1充电在前面。给定重新排序的指令,它首先设置flag=true。在它到达“this.in

    • 我对下面的代码段有一个问题。结果可能有一个结果[0,1,0](这是用JCStress执行的测试)。那么这是怎么发生的呢?我认为数据写入(data=1)应该在Actor2(guard2=1)中写入到guard2之前执行。我说得对吗?我问,因为很多时候我读到挥发物周围的说明没有重新排序。此外,根据这一点:http://tutorials.jenkov.com/java-concurrency/vola

    • 问题内容: 据我所知,在Java中,volatile变量使线程直接对主CPU进行读/写操作(而不是在每个线程的缓存中),因此使其更改对其他线程可见。 我不知道的是:因此,为什么这项工作(易失性)可以阻止编译器/ CPU对代码的重新排序语句。 谢谢 :) 问题答案: 这是一个很好的示例,说明了禁止重新排序的目的是要解决的问题(从此处获取): 在此示例中,为易失性,但不是。如果作者和阅读者同时执行并且

    • 我决定要对一个特定的函数进行基准测试,所以我天真地编写了这样的代码: 一位同事指出,我应该将和变量声明为,以避免代码重新排序。例如,他建议优化器可以像这样有效地重新排序代码: 起初,我怀疑这种极端的重新排序是允许的,但经过一些研究和实验,我知道是允许的。 但volatile感觉不是正确的解决方案;volatile真的只是用于内存映射I/O吗? 然而,我添加了< code>volatile,发现不仅

    • 我正在用java编写一些代码,它检查一个由51个对象组成的数组,名为,这些对象是从右向左移动到x:200px位置的播放器的圆圈。我想使它这样,玩家被判分或扣分的基础上,他们的按钮按下的时间与一个节拍的位置相比,到目前为止,我有以下几个: 这种方法会导致几个问题,因为范围重叠,以此类推,按下按钮通常会输出如下内容: 然而,我希望它一次只检查一个位置,例如最靠近播放器的位置,或者是迭代器,用于检查数组

    • 问题内容: 我有一个关联数组 在我在此数组上使用json_encode之后。密钥已排序,尽管我将其作为JSON对象获取。 有办法防止这种行为吗? 问题答案: 没有任何标准表明必须按一定顺序进行。 注意:我们正在谈论的是PHP函数,但结果基本上是javascript,因此有关不存在的标准的声明也适用。 顺便说一句:我已经用以下代码对其进行了测试。PHP本身似乎并没有对数组进行排序,firefox也没