Reputation: 638
In the below code will Java ensure that latest copy of a
is visible to the thread which calls getAB()
?
I understand that the values returned by getAB()
might not be the same as set by setAB
, but will Java ensure that the value of a
seen by other thread will always either be more recent or consistent with the value of b
?
public class Pair {
private int a;
private int b;
public Pair() {
super();
}
public void setAB(int a, int b) {
this.a = a;
synchronized (this) {
this.b = b;
}
}
public int[] getAB() {
int[] arr = new int[2];
arr[0] = a;
synchronized (this) {
arr[1] = b;
}
return arr;
}
}
Followup question: what happens if we move the arr[0] = a;
statement to after the synchronized
block?
Like this ...
public int[] getAB() {
int[] arr = new int[2];
synchronized (this) {
arr[1] = b;
}
arr[0] = a;
return arr;
}
Upvotes: 0
Views: 144
Reputation: 719239
Does java also guarantee that all variable changes before synchronized will be visible to the next thread which synchronizes on same object?
Yes it does ... assuming the mutex has been acquired by the next thread.
However. In your example getAB
is using a
before it has synchronized on this
, so arr[0] = a
could assign a stale value.
Assuming that setAB
is called before getAB
, the happens before relationships in your example will be:
this.a = a;
HB this.b = b;
HB released mutex in first thread
HB acquired mutex in second thread
HB arr[1] = b;
and separately
arr[0] = a;
HB arr[1] = b;
From this we can deduce that
this.b = b; HB arr[1] = b;
but we cannot deduce that
this.a = a; HB arr[0] = a; // FALSE!
Then you move arr[0] = a;
to after the synchronized
block, the updated value of a
is now guaranteed to be visible.
I won't reproduce the full "happens before analysis", but now we get
arr[1] = b; HB arr[0] = a;
and we can deduce that
this.a = a; HB arr[0] = a; // NOW TRUE!
Having said this, it is generally NOT recommended that you write code that relies on careful analysis of happens before relationships etcetera. It is better to use the higher level synchronization classes, or (as in this case) just do all of the reading and writing of shared variables inside the synchronized
block.
(Generally speaking, the performance benefit you get from clever implementations of concurrency is usually tiny compared to overall application performance. And the long term cost of finding and fixing Heisenbugs caused by subtle synchronization code flaws can be huge.)
Upvotes: 2