Why does it never throw an AssertionError even after it has been running for so long?

Here is the source code

//@author Brian Goetz and Tim Peierls
@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};
    }

    // I removed the synchronized from here
    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.");
        }
    }
}
+4
2

, , , , ; jre CPU, . , , - , .

/ , , ( , ). , , .

final , setters, . , , , x y , get ( SafePoint )

+4

, JMM, - undefined.

, . , HotSpot C2. , ( ):

  0x00007f6b38516fbd: lock addl $0x0,(%rsp)     ;*synchronization entry
                                                ; - java.util.Random::<init>@-1 (line 105)
                                                ; - com.test.SafePointProblem$lambda::run@4 (line 19)

  0x00007f6b38516fc2: mov     0x10(%r10),%rax   ;*invokevirtual compareAndSwapLong
                                                ; - java.util.concurrent.atomic.AtomicLong::compareAndSet@9 (line 147)
                                                ; - java.util.Random::next@32 (line 204)
                                                ; - java.util.Random::nextInt@17 (line 390)
                                                ; - com.test.SafePointProblem$lambda

JIT- HotSpot, , , . Random::next ( CAS), reset .

"?" .

+2

Source: https://habr.com/ru/post/1692156/


All Articles