$ java -cp target/classes com.ankurm.atomics.AbaProblemDemo

=== Part 1: a real ABA race against TreiberStack ===
Initial stack (top first): [A, B, C]
Main thread popped, legitimately: "A", then "B"
Stack after those two real pops: [C]
Main thread pushed the SAME "A" node object back: [A, C]
Thread 1's stale CAS result: CAS succeeded, pop() would have returned "A"
Stack contents after Thread 1's stale CAS: [B, C]
"B" is back in the stack even though the main thread already popped it and
nobody ever pushed it again - Thread 1's CAS matched on reference identity
alone (top was "A" both times it looked) and blindly installed a newTop
("B") that was computed from a read that happened before two pops and a
push it never saw. "A" was also just handed out twice: once to the main
thread's first pop(), once to Thread 1's stale one.

=== Part 2: AtomicStampedReference detects the same shape of race ===
Reader captured: ref="A", stamp=0
After a concurrent A -> B -> A round trip: ref="A", stamp=2 (reference is back to "A", but the stamp moved on)
A plain AtomicReference.compareAndSet("A", "Z") would see reference == "A" and succeed: true
AtomicStampedReference.compareAndSet("A", "Z", 0, 1) actually succeeded: false (false is correct - the stamp proves a change happened in between, even though the reference alone looks unchanged)
