程序员求职经验分享与学习资料整理平台

网站首页 > 文章精选 正文

Java并发工具:AtomicStampedReference

balukai 2025-05-10 20:00:09 文章精选 4 ℃

AtomicStampedReference

AtomicStampedReference 是 Java 中 java.util.concurrent.atomic 包下提供的一个类,用于解决 ABA 问题。ABA 问题是指在并发环境下,某个变量从 A 变为 B 再变回 A,尽管最终值看起来没有变化,但中间发生了改变,这对依赖于比较并交换机制(CAS)的无锁算法可能造成困扰。

基本概念

  • 版本戳:AtomicStampedReference 通过引入一个整型的“版本号”或称为“戳”,来跟踪对象引用的变化。每次更新引用时,也会更新这个版本号,这样即使引用的值回到了原来的状态,版本号也会不同,从而避免了 ABA 问题。
  • 构造函数
  • AtomicStampedReference(V initialRef, int initialStamp):创建一个新的 AtomicStampedReference,带有给定的初始值和戳。
  • 主要方法
  • V getReference():获取当前引用。
  • int getStamp():获取当前戳。
  • V get([int[] stampHolder]):除了返回当前引用外,还可以通过 stampHolder 数组的第一个元素获取当前戳。
  • boolean weakCompareAndSet(V expectedReference, V newReference, int expectedStamp, int newStamp):原子地设置引用和戳,如果当前引用等于预期引用且当前戳等于预期戳,则更新为新引用和新戳。这是一个弱的 CAS 操作,可能会失败而不保证立即重试。
  • boolean compareAndSet(V expectedReference, V newReference, int expectedStamp, int newStamp):类似于 weakCompareAndSet,但是提供强保证,即如果条件满足,则操作必定成功。
  • void set(V newReference, int newStamp):直接设置新的引用和戳,不进行任何检查。

示例代码

使用 AtomicStampedReference 来解决 ABA 问题:

import java.util.concurrent.atomic.AtomicStampedReference;

public class ABADemo {
    public static void main(String[] args) throws InterruptedException {
        AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100, 0);

        Thread t1 = new Thread(() -> {
            int[] stampHolder = new int[1];
            atomicStampedReference.get(stampHolder);
            System.out.println("Initial Value: " + atomicStampedReference.getReference() + ", Stamp: " + stampHolder[0]);

            boolean success = atomicStampedReference.compareAndSet(100, 101, stampHolder[0], stampHolder[0] + 1);
            System.out.println("First Update Success: " + success + ", New Value: " + atomicStampedReference.getReference() + ", Stamp: " + atomicStampedReference.getStamp());

            success = atomicStampedReference.compareAndSet(101, 100, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);
            System.out.println("Second Update Success: " + success + ", New Value: " + atomicStampedReference.getReference() + ", Stamp: " + atomicStampedReference.getStamp());
        });

        Thread t2 = new Thread(() -> {
            int[] stampHolder = new int[1];
            atomicStampedReference.get(stampHolder);
            try {
                Thread.sleep(100); // 确保t1先执行
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            boolean success = atomicStampedReference.compareAndSet(100, 1042, stampHolder[0], stampHolder[0] + 1);
            System.out.println("Update by t2 Success: " + success + ", New Value: " + atomicStampedReference.getReference() + ", Stamp: " + atomicStampedReference.getStamp());
        });

        t1.start();
        t2.start();

        t1.join();
        t2.join();
    }
}

在这个示例中,线程 t1 首先将值从 100 更改为 101 并增加戳,然后又改回 100 并再次增加戳。与此同时,线程 t2 尝试将值从 100 改为 1042。由于 AtomicStampedReference 跟踪了版本戳,所以 t2 的尝试会失败,因为它持有的是旧的戳值。这有效地防止了 ABA 问题的发生。

最近发表
标签列表