AtomicStampedReference

利用版本戳的形式记录了每次改变以后的版本号,这样的话就不会存在ABA问题了。这就是AtomicStampedReference的解决方案。AtomicMarkableReference跟AtomicStampedReference差不多, AtomicStampedReference是使用pair的int stamp作为计数器使用,AtomicMarkableReference的pair使用的是boolean mark。 还是那个水的例子,AtomicStampedReference可能关心的是动过几次,AtomicMarkableReference关心的是有没有被人动过,方法都比较简单。

  1. public class Test36 {
  2. static AtomicStampedReference<String> ref = new AtomicStampedReference<>("A", 0);
  3. public static void main(String[] args) throws InterruptedException {
  4. log.debug("main start...");
  5. // 获取值 A
  6. String prev = ref.getReference();
  7. // 获取版本号
  8. int stamp = ref.getStamp();
  9. log.debug("版本 {}", stamp);
  10. // 如果中间有其它线程干扰,发生了 ABA 现象
  11. other();
  12. sleep(1);
  13. // 尝试改为 C
  14. log.debug("change A->C {}", ref.compareAndSet(prev, "C", stamp, stamp + 1));
  15. }
  16. private static void other() {
  17. new Thread(() -> {
  18. log.debug("change A->B {}", ref.compareAndSet(ref.getReference(), "B", ref.getStamp(), ref.getStamp() + 1));
  19. log.debug("更新版本为 {}", ref.getStamp());
  20. }, "t1").start();
  21. sleep(0.5);
  22. new Thread(() -> {
  23. log.debug("change B->A {}", ref.compareAndSet(ref.getReference(), "A", ref.getStamp(), ref.getStamp() + 1));
  24. log.debug("更新版本为 {}", ref.getStamp());
  25. }, "t2").start();
  26. }
  27. }