Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Synchronized and the scope of visibility

I've been reading up on Java concurrency and had forgot the fact that synchronization blocks in two threads using the same lock also affect the visibility of variables, even though they were not defined as "volatile". If I have code like this

Object lock = new Object();
boolean a = false, b = false, c = false;

void threadOne() {

   a = true;
   synchronized(lock) {
      b = true;
   }
   c = true;

}

void threadTwo() {

   while (true) {
      synchronized(lock) {
         if (a && b && c) break;
      }
   } 

}

... and threadOne and threadTwo will be called by different threads:

  1. Is it guaranteed that the code will break out of the while loop?

  2. What if we remove variable c out of the equation? I'm wondering if only b is guaranteed to be visible in threadTwo because it was inside the synchronization block.

like image 490
StrangeLoop Avatar asked Dec 06 '25 06:12

StrangeLoop


1 Answers

Is it guaranteed that the code will break out of the while loop?

No. The Java memory model is defined in terms of "happens before" relationships:

Two actions can be ordered by a happens-before relationship. If one action happens-before another, then the first is visible to and ordered before the second.

The spec goes on to say:

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

where hb stands for happens-before, and

An unlock action on monitor m synchronizes-with all subsequent lock actions on m (where "subsequent" is defined according to the synchronization order).

Also note that:

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

So in your example, the synchronized(lock) around b will establish a happens-before relationship for the following read, and thus the value of b is guaranteed to be visible in other threads that also use synchronized(lock). Explicitly,

hb(write to b in threadOne, unlock in threadOne) AND 
hb(unlock in threadOne, lock in threadTwo) AND 
hb(lock in threadTwo, read from a in threadTwo) IMPLIES 
hb(write to b in threadOne, read from b in threadTwo) 

Similarly, a will be guaranteed to be visible to the other thread. Explicitly,

hb(write to a in threadOne, lock in threadOne) AND 
hb(lock in threadOne, unlock in threadOne) AND 
hb(unlock in threadOne, lock in threadTwo) AND 
hb(lock in threadTwo, read a in threadTwo) IMPLIES 
hb(write to a in threadOne, read a in threadTwo). 

The write and then subsequent read of c does not have a happens-before relationship, so therefore, according to the spec, the write to c is not necessarily visible to threadTwo.

What if we remove variable c out of the equation? I'm wondering if only b is guaranteed to be visible in threadTwo because it was inside the synchronization block.

Yes, see above.

like image 93
Alex DiCarlo Avatar answered Dec 07 '25 20:12

Alex DiCarlo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!