Volatile guarantees and out-of-order execution [duplicate]

ぃ、小莉子 提交于 2019-11-27 02:59:41

No, you will never get a NPE. This is because volatile also has the memory-effect of introducing a happens-before relationship. In other words, it will prevent reordering of

a = one;
b = two;

The statements above, will not be re-ordered, and all threads will observe value one for a if b already has value two.

Here is a thread in which David Holmes explains this:
http://markmail.org/message/j7omtqqh6ypwshfv#query:+page:1+mid:34dnnukruu23ywzy+state:results

EDIT (response to the follow-up): What Holmes is saying is, the compiler could in theory do a reorder if there were only thread A. However, there ARE other threads, and they CAN detect the reordering. That is why the compiler is NOT allowed to do that reordering. The java memory model requires the compiler specifically to make sure that no thread will ever detect such reordering.

But what if one is calling doIt() from another thread than the one calling setBothNonNull(...) ?

No, you will still NEVER have a NPE. volatile semantics do impose inter-thread ordering. Meaning that, for all existing thread, assignment of one happens before the assignment of two.

Am I correct in my understanding that due to out-of-order execution I can get a NullPointerException? In other words: there's no guarantee that because I read a non-null "b" I'll read a non-null "a"?

Assuming that the values assigned to a and b or non-null, I think your understanding is not correct. The JLS says this:

(1) If x and y are actions of the same thread and x comes before y in program order, then hb(x, y).

(2) If an action x synchronizes-with a following action y, then we also have hb(x, y).

(3) If hb(x, y) and hb(y, z), then hb(x, z).

and

(4) A write to a volatile variable (§8.3.1.4) v synchronizes-with all subsequent reads of v by any thread (where subsequent is defined according to the synchronization order).

Theorem

Given that thread #1 has called setBoth(...); once, and that the arguments were non-null, and that thread #2 has observed b to be non-null, then thread #2 cannot then observe a to be null.

Informal Proof

  1. By (1) - hb(write(a, non-null), write(b, non-null)) in thread #1
  2. By (2) and (4) - hb(write(b, non-null), read(b, non-null))
  3. By (1) - hb(read(b, non-null), read(a, XXX)) in thread #2,
  4. By (4) - hb(write(a, non-null), read(b, non-null))
  5. By (4) - hb(write(a, non-null), read(a, XXX))

In other words, the write of a non-null value to a "happens-before" the read of the value (XXX) of a. The only way that XXX can be null, is if there was some other action writing null to a such that hb(write(a,non-null), write(a,XXX)) and hb(write(a,XXX), read(a,XXX)). And this is impossible according to the problem definition, and therefore XXX cannot be null. QED.

Explanation - the JLS states that the hb(...) ("happens-before") relationship does not totally forbid reordering. However, if hb(xx,yy), then reordering of actions xx and yy is only allowed if the resulting code has the same observable effect as the original sequence.

I found the following post that explains that volatile has the same ordering semantics as synchronized in this case. Java Volatile is Powerful

While Stephen C's and the accepted answers are good and pretty much cover it, it's worth making an important note that variable a doesn't have to be volatile - and you still won't get an NPE. This is because there will be a happens-before relationship between a = one and b = two, regardless of whether a is volatile. So Stephen C's formal proof still applies, just no need for a being volatile.

I read this page and found a non-volatile & non-synchronized version of your question:

class Simple {
    int a = 1, b = 2;
    void to() {
        a = 3;
        b = 4;
    }
    void fro() {
        System.out.println("a= " + a + ", b=" + b);
    }
}

fro may obtain either 1 or 3 for the value of a, and independently may obtain either 2 or 4 for the value of b.

(I realize this doesn't answer your question but it complements it.)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!