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

易失性Java重新排序

宫弘亮
2023-03-14
  • a)为什么除了“00”之外还有其他输出?
  • b)如何修改代码以便始终打印“00”。
 boolean flag = false;

    void changeVal(int val) {
        if(this.flag){
            return;
        }
        this.initialInt = val;
        this.flag = true;
    }

    int initialInt = 1;

    class MyThread extends Thread {
        public void run(){
            changeVal(0);
            System.out.print(initialInt);
        }
    }

    void execute() throws Exception{
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();
        t1.start(); t2.start(); t1.join(); t2.join();
        System.out.println();
    }

对于a)我的回答是:在没有任何volatile/同步构造的情况下,编译器可以重新排序一些指令。特别是“this.initialint=val;”和“this.flag=true;”可以切换,这样就可以发生这种情况:线程都启动了,t1充电在前面。给定重新排序的指令,它首先设置flag=true。在它到达“this.initialint=val;”的最后一个语句之前另一个线程跳入,检查if条件并立即返回,从而打印未更改的initialInt值1。除此之外,我认为,如果没有任何volatile/同步,t2是否会看到t1中对initialInt执行的赋值,因此它也可能打印“1”作为默认值,这是不确定的。

对于b)我认为这面旗帜可能会变得不稳定。我已经了解到,当t1写到一个volatile变量设置标志=true,然后t2在if-语句中读出这个volatile变量时,将看到在volatile写之前执行的任何写操作,因此initialInt也=val。因此,t2已经看到它的initialInt值更改为0,并且必须始终打印0。然而,只有当volatile的使用成功地防止了我在a)中描述的任何重新排序时,这才会起作用。我读过volatile完成了这些事情,但我不确定在没有任何进一步的同步块或任何这样的锁的情况下,这是否总是起作用。从这个答案中,我得出结论,在volatile存储区(所以这个.flag=true)被重新排序之前发生的任何事情都不能出现在它之外。在这种情况下,initialInt=val不能下移,我应该是正确的,对吗?或者不对?:)

非常感谢你的帮助。我期待着你的答复。

共有1个答案

夏朝
2023-03-14

示例将始终打印00,因为您在打印之前执行changeval(0)

要模拟可能不打印00的情况,需要将initialint=1;移动到线程的上下文中,如下所示:

class MyThread extends Thread {
        public void run(){
            initialInt = 1;
            changeVal(0);
            System.out.print(initialInt);
        }
    }

现在您可能会遇到争用条件,在initialInt在thread2中打印之前,将它在thread1中设置回1

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

  • 对易失性字段的写和读分别防止了在易失性字段之前和之后的读/写的重新排序。在写到易失性变量之前的变量读/写不能被重新排序为在它之后发生,在从易失性变量读到之后的读/写不能被重新排序为在它之前发生。但是这种禁止的范围是什么呢?正如我所理解的,volatile变量只能在使用它的块内防止重新排序,对吗? 为了清楚起见,让我举一个具体的例子。假设我们有这样的代码: 让我再举一个具体的例子来说明范围以澄清事情

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

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

  • 在阅读了这个问题和这个(尤其是第二个答案)之后,我对volatile及其关于记忆障碍的语义感到非常困惑。 在上面的例子中,我们写入一个易失性变量,这会导致一个mitch,这反过来会将所有挂起的存储缓冲区/加载缓冲区刷新到主缓存,使其他缓存行无效。 然而,非易失性字段可以优化并存储在寄存器中,例如?那么,我们如何才能确保给定一个写入易失性变量之前的所有状态变化都是可见的呢?如果我们有1000件东西呢

  • 问题内容: 如何使数组易失?因为正如我所了解的那样,使数组易失是不安全的吗? 问题答案: 将数组声明为volatile并 不能 对其字段进行volatile访问。您是在声明引用本身是可变的,而不是元素。 换句话说,你声明 挥发性组 的元素,而不是一个 集易挥发元素 。 解决方案是在要使用整数的情况下使用。另一种方法(但有点难看)是每次您编辑字段时都将对数组的引用重写。 您可以这样做: (就像我说的