1

Because ordinary reading and writing after volatile writing does not prohibit reordering, may b=3 in the following code be reordered before a=2+b?

volatile int a = 1;
int b = 2;

private void demo () {
    a = 2 + b;
    b = 3;
}
ruakh
  • 175,680
  • 26
  • 273
  • 307
嘉图李
  • 11
  • 1
  • 1
    Please post your code as formatted text and not as image. – Zabuzard Oct 14 '21 at 16:15
  • I want to say "no, `b` cannot be reordered" but I'm not 100% sure. Look up "program order", which says that reads and writes within one single thread of execution will always be observed in the order they occur within the program. Because of this is seems unlikely that an optimizer would determine that `b` can be moved up in its assignment. – markspace Oct 14 '21 at 16:33
  • @markspace: I think you're misinterpreting that; Java does *not* guarantee that things are always observed as occurring in "program order". Per https://docs.oracle.com/javase/specs/jls/se17/html/jls-17.html#jls-17.4.3, "**If a program has no data races**, then all executions of the program will appear to be sequentially consistent." [emphasis mine]. – ruakh Oct 14 '21 at 16:52
  • @ruakh While Java doesn't actually guarantee program order, what that section of the JLS is saying is that *you* the programmer can't tell the difference between program order and whatever optimization is used. Thus, you as a programmer only have to reason about program order, the JLS guarantees that its internal, optimized order will be indistinguishable. (This is, of course, absent any interference from an external thread.) – markspace Oct 14 '21 at 17:47
  • Well we don't actually have any other threads in this example, so it's a bit hard to say what the OP is really asking. If this example is called directly from `public static void main( String... a )` for example, then there's only one thread and program order is the only execution possible. – markspace Oct 14 '21 at 18:03
  • @markspace: Yes, agreed. Above, you wrote "reads and writes within one single thread of execution" and "will always be observed in the order [...]"; I now think that what you meant to write was "will always be observed *by that thread* in the order [...]", and if so, then I agree. I think the OP is getting confused by exactly that subtlety. (But I could be wrong. Walter Tross and pveentjer seem to have interpreted the question the same way you did.) – ruakh Oct 14 '21 at 18:10
  • Again, without any other threads shown, I think it's important to point out that the JVM doesn't just maliciously rearrange the order of reads and writes. Within a single thread, absent any interference (and none is shown), there isn't any observable reordering possible. – markspace Oct 14 '21 at 18:15
  • @markspace: Yes, agreed. – ruakh Oct 14 '21 at 18:29

2 Answers2

1

Not exactly.

The important thing to be aware of is that given two events, two threads can observe those two events in different order.

Since both of these writes are within a single thread, that thread is guaranteed to observe the two writes in the order that they appear. So there's no risk that the statement a = 2 + b will use the about-to-be-set value of b (namely 3) instead of its already-set value (presumably 2, though it can obviously depend on other code that you haven't shown).

This means that a will end up being set to 4, as desired, not to 5.

But other threads can certainly observe these writes out of order; if another thread has System.out.println("a = " + this.a + ", b = " + this.b), and there's no other synchronization here, then it's absolutely possible for that thread to print a = 1, b = 3, showing the original value of a but the new value of b.

ruakh
  • 175,680
  • 26
  • 273
  • 307
0

The sequential semantics of a program can't be violated. Based on your question, I have the impression that the demo method is executed by a single thread and hence the the volatile nature of a is not relevant.

If I simplify your code a bit into individual loads/stores:

r1=b
a=2+r1
b=3

The only possible allowed outcome is a=4,b=3.

Then b=3 and a=2+r1 can be reordered since it doesn't change the outcome. But if b=3 would jump in front of r1=b, then the outcome of this execution would be a=5, b=3. And this is a violation of the sequential semantics of the program.

For more information, see my answer in this post: Why doesn't this example from Java Concurrency in Practice allow reordering

pveentjer
  • 10,545
  • 3
  • 23
  • 40