Volatile Java reordering

huangapple go评论62阅读模式
英文:

Volatile Java reordering

问题

Sure, here's the translated content:

首先,让我说一下,我意识到这是一个相当常见的话题,但在搜索时,我找不到另一个问题来澄清以下情况,非常抱歉如果这是一个可能的重复问题,但是这里是你要的:

我对并发性很陌生,已经收到以下代码以回答问题:

  • a)除了“00”之外,为什么可能出现其他任何输出?
  • b)如何修改代码以始终打印“00”。

对于a),我的答案是:在没有任何volatile/同步构造的情况下,编译器可以重新排序一些指令。特别是,“this.initialInt = val;”和“this.flag = true;”可能会被交换,因此可能出现以下情况:线程都启动了,t1领先。在重新排序的指令中,它首先设置flag = true。现在,在达到“this.initialInt = val;”的最后一条语句之前,其他线程介入,检查if条件并立即返回,因此打印未更改的initialInt值为1。此外,我认为没有volatile/同步,不能确定t2是否可能看到在t1中对initialInt的分配,因此它也可能打印默认值为“1”。

对于b),我认为flag可以被标记为volatile。我已经了解到,当t1写入一个volatile变量设置flag = true时,t2在if语句中读取此volatile变量时将看到在volatile写之前执行的任何写操作,因此也包括initialInt = val。因此,t2将已经看到其initialInt值更改为0,必须始终打印0。
然而,这只有在volatile成功防止如a)中所描述的重新排序时才有效。我已经了解到volatile可以实现这样的功能,但不确定在没有进一步的同步块或任何锁定的情况下是否始终有效。从这个答案中,我了解到在volatile存储之前(因此this.flag = true),不会重新排序任何发生的事情。在这种情况下,initialInt = val不能移动下来,我应该是正确的,对吗?或者不是? Volatile Java reordering

非常感谢您的帮助。我期待您的回复。

英文:

Firstly let me say that I am aware of this being a fairly common topic here but searching for it I couldn't quite find another question that clarifies the following situation. I am very sorry if this is a possible duplicate but here you go:

I am new to concurrency and have been given the following code in order to answer questions:

  • a) Why any other output aside from "00" would be possible?
  • b) How to amend the code so that "00" will ALWAYS print.
 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();
    }

For a) my answer would be the following: In the absence of any volatile / synchronization construct the compiler could reorder some of the instructions. In particular, "this.initialInt = val;" and "this.flag = true;" could be switched so that this situation could occur: The threads are both started and t1 charges ahead. Given the reordered instructions it first sets flag = true. Now before it reaches the now last statement of "this.initialInt = val;" the other thread jumps in, checks the if-condition and immediately returns thus printing the unchanged initialInt value of 1. Besides this, I believe that without any volatile / synchronization it is not for certain whether t2 might see the assignment performed to initialInt in t1 so it may also print "1" as the default value.

For b) I think that flag could be made volatile. I have learned that when t1 writes to a volatile variable setting flag = true then t2, upon reading out this volatile variable in the if-statement will see any write operations performed before the volatile write, hence initialInt = val, too. Therefore, t2 will already have seen its initialInt value changed to 0 and must always print 0.
This will only work, however, if the use of volatile successfully prevents any reordering as I described in a). I have read about volatile accomplishing such things but I am not sure whether this always works here in the absence of any further synchronized blocks or any such locks. From this answer I have gathered that nothing happening before a volatile store (so this.flag = true) can be reordered as to appear beyond it. In that case initialInt = val could not be moved down and I should be correct, right? Or not ? Volatile Java reordering

Thank you so much for your help. I am looking forward to your replies.

答案1

得分: 1

这个示例会始终打印00,因为在打印之前执行了changeVal(0)

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

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

现在可能会出现竞争条件,会在thread1中将initialInt设置回1,然后在thread2中打印。

另一种可能导致竞争条件的替代方法,但更难理解,是交换设置标志和设置值的顺序:

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

This example will alway print 00 , because you do changeVal(0) before the printing .

to mimic the case where 00 might not be printed , you need to move initialInt = 1; to the context of a thread like so :

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

now you might have a race condition , that sets initialInt back to 1 in thread1 before it is printed in thread2

another alternative that might results in a race-condition but is harder to understand , is switching the order of setting the flag and setting the value

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

答案2

得分: 1

没有明确的同步,因此可能出现各种交错情况,并且一个线程所做的更改不一定对另一个线程可见,因此有可能在对flag的更改可见之前对initialInt的更改可见,导致10或01的输出,以及00的输出。11是不可能的,因为对变量的操作对执行它们的线程可见,并且changeVal(0)的效果始终对至少一个线程可见。

changeVal声明为同步的,或者将flag声明为volatile会解决这个问题。flag是在临界区中最后更改的变量,因此将其声明为volatile会创建一个发生在关系,使对initialInt的更改可见。

英文:

There are no explicit synchronizations, so all kinds of interleavings are possible, and changes made by one thread are not necessarily visible to the other so, it is possible that the changes to flag are visible before the changes to initialInt, causing 10 or 01 output, as well as 00 output. 11 is not possible, because operations performed on variables are visible to the thread performing them, and effects of changeVal(0) will always visible for at least one of the threads.

Making changeVal synchronized, or making flag volatile would fix the issue. flag is the last variable changed in the critical section, so declaring it as volatile would create a happened-before relationship, making changes to initialInt visible.

huangapple
  • 本文由 发表于 2020年7月30日 04:34:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/63162001.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定