原子类的 ABA 问题
原子引用
public class AtomicReferenceDemo { public static void main(String[] args) { User cuzz = new User("cuzz", 18); User faker = new User("faker", 20); AtomicReference<User> atomicReference = new AtomicReference<>(); atomicReference.set(cuzz); System.out.println(atomicReference.compareAndSet(cuzz, faker)); // true System.out.println(atomicReference.get()); // User(userName=faker, age=20) } }
ABA问题的产生
/** * 当有一个值从 A 改为 B 又改为 A,这就是 ABA 问题 **/ public class ABADemo { private static AtomicReference<Integer> atomicReference = new AtomicReference<>(100); public static void main(String[] args) { new Thread(() -> { atomicReference.compareAndSet(100, 101); atomicReference.compareAndSet(101, 100); }).start(); new Thread(() -> { // 保证上面线程先执行 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } atomicReference.compareAndSet(100, 2019); System.out.println(atomicReference.get()); // 2019 }).start(); } }
时间戳原子引用
/** * 我们先保证两个线程的初始版本为一致,后面修改是由于版本不一样就会修改失败 **/ public class ABADemo2 { private static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100, 1); public static void main(String[] args) { new Thread(() -> { int stamp = atomicStampedReference.getStamp(); System.out.println(Thread.currentThread().getName() + " 的版本号为:" + stamp); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } atomicStampedReference.compareAndSet(100, 101, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1 ); atomicStampedReference.compareAndSet(101, 100, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1 ); }).start(); new Thread(() -> { int stamp = atomicStampedReference.getStamp(); System.out.println(Thread.currentThread().getName() + " 的版本号为:" + stamp); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } boolean b = atomicStampedReference.compareAndSet(100, 2019, stamp, stamp + 1); System.out.println(b); // false System.out.println(atomicStampedReference.getReference()); // 100 }).start(); } }