atomics: Java Atomics and VarHandle companion code
AtomicLong/LongAdder/VarHandle counters benchmarked against the synchronized and ReentrantLock baselines from the locks module, a deterministic ABA race against a hand-rolled Treiber stack plus the AtomicStampedReference fix, and a VarHandle access-modes demo (plain/opaque/acquire-release/volatile). Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01FhzLY5p6okFva3qsnsRyvM
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
$ 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)
|
||||
Reference in New Issue
Block a user