Here is the source code
@ThreadSafe
public class SafePoint {
@GuardedBy("this") private int x, y;
private SafePoint(int[] a) {
this(a[0], a[1]);
}
public SafePoint(SafePoint p) {
this(p.get());
}
public SafePoint(int x, int y) {
this.set(x, y);
}
public synchronized int[] get() {
return new int[]{x, y};
}
public synchronized void set(int x, int y) {
this.x = x;
this.y = y;
}
}
It is wonderful here that private int x, y is not final, because the set method in the constructor causes the event to occur before the relation when get is called, because they use the same lock.
Now here is the modified version and the main method, which I expected to throw an AssertionError after it was launched a bit, because I deleted the synchronized keyword in the set method. I made it closed so that the constructor would be the only one who called it if someone pointed out that because of it it is not thread safe, which is not the subject of my question.
, , AssertionErrors . , - , , , , x y . - , AssertionError ?
public class SafePointProblem {
static SafePoint sp = new SafePoint(1, 1);
public static void main(String[] args) {
new Thread(() -> {
while (true) {
final int finalI = new Random().nextInt(50);
new Thread(() -> {
sp = new SafePoint(finalI, finalI);
}).start();
}
}).start();
while (true) {
new Thread(() -> {
sp.assertSanity();
int[] xy = sp.get();
if (xy[0] != xy[1]) {
throw new AssertionError("This statement is false 1.");
}
}).start();
}
}
}
class SafePoint {
private int x, y;
public SafePoint(int x, int y) {
this.set(x, y);
}
public synchronized int[] get() {
return new int[]{x, y};
}
private void set(int x, int y) {
this.x = x;
this.y = y;
}
public void assertSanity() {
if (x != y) {
throw new AssertionError("This statement is false2.");
}
}
}