4

Given the below code:

public class Test {

  private volatile boolean a;

  private volatile boolean b;

  private void one () {
    a = true;
    System.out.println (b);
  }

  private void two () {
    b = true;
    System.out.println (a);
  }

  public static void main (String[] args) throws Exception {
    Test s = new Test ();
    Thread one = new Thread (s::one);
    Thread two = new Thread (s::two);
    one.start ();
    two.start ();
    one.join ();
    two.join ();
  }

}

Is it guaranteed (under the Java Memory Model) that at least one thread prints true?

I understand that there is a happens-before relationship between a write to a volatile variable and a read that sees the updated value, but it seems me it is possible for none of the threads to see the updated value, although I couldn't make it happen.

Étienne Miret
  • 6,448
  • 5
  • 24
  • 36
  • I think it must print at least one `true`, though I wouldn't actually write code like this. If `one` prints `false`, then it has to already executed `a=true;`, so the other thread must print `true`. If the two threads interleave, they can both print `true`, but I don't see a path that lets both print `false`. – markspace Dec 04 '18 at 18:51
  • I don't see the conflict here. There's no way for either to be locked out, since the volatile variables will simply be updated and released, e.g. once `b = true` is complete, it releases the lock on b instead of retaining it while waiting for a to be released – Matthew Kerian Dec 04 '18 at 18:53
  • I think your question may be answered [here](https://stackoverflow.com/questions/8769570/volatile-piggyback-is-this-enough-for-visiblity/8769692#8769692) – Tom Drake Dec 04 '18 at 18:53
  • It's not piggybacking. I think the crux here is whether the `println` can be re-ordered above the assignment of a volatile, and I think the answer is "no." – markspace Dec 04 '18 at 18:56
  • That's what I'm saying. The thing is, program order is guaranteed, and only re-orderings are allowed that don't violate the same result from program order. Since re-ordering here produces a different result, I think it's disallowed. I'd love to find a more explicit rule in the memory model though. @AndyTurner – markspace Dec 04 '18 at 18:59

1 Answers1

4

Yes it's guaranteed.

To prove this, assume without loss of generality that thread 1 prints false. Since b is volatile, this means that thread 1 executed the print before thread 2's write of b. But if this is the case, then by the time thread 2 executes its own print, a must have already been set to true by thread 1.

Note that the prints cannot be reordered before the writes as per JLS §17.4.5:

  • If x and y are actions of the same thread and x comes before y in program order, then hb(x, y) [x happens-before y].

Moreover, the write to a or b will be immediately visible to the other thread:

  • A write to a volatile field (§8.3.1.4) happens-before every subsequent read of that field.
arshajii
  • 127,459
  • 24
  • 238
  • 287
  • Can you clarify which bit of 17.4.5 says they can't be reordered? – Andy Turner Dec 04 '18 at 19:10
  • @AndyTurner Just added a quote. – arshajii Dec 04 '18 at 19:11
  • "A write to a volatile field (§8.3.1.4) happens-before every subsequent read of that field. " That says nothing about a write to a field happening before the read of another field. – Andy Turner Dec 04 '18 at 19:12
  • Also in 17.4.5: "It should be noted that the presence of a happens-before relationship between two actions does not necessarily imply that they have to take place in that order in an implementation." – Andy Turner Dec 04 '18 at 19:13
  • "If x and y are actions of the same thread and x comes before y in program order, then hb(x, y) [x happens-before y]." I guess that's the part I was missing. – Étienne Miret Dec 04 '18 at 19:16
  • @AndyTurner Yes, but if one thread prints false, then the read of that variable must've happened-before the write in the other thread, so that other thread must then print true. As for your 2nd comment -- let me look at it a bit more. Have to put my language lawyer hat on now :P – arshajii Dec 04 '18 at 19:16
  • @AndyTurner The second part of your quote is "If the reordering produces results consistent with a legal execution, it is not illegal." -- As far as I can tell, such a reordering would not produce a legal execution, as it would change the program behavior. – arshajii Dec 04 '18 at 19:22
  • @arshajii reordering is legal if and only if it aligned with Java memory model. It may be legal and at the same time change program behavior if program is not thread-safe. – Ivan Dec 04 '18 at 20:08