AtomicReference

本文介绍了Java中的AtomicReference类,用于在多线程环境中原子性地更新引用类型对象,以及其主要方法如get(),set(),getAndSet(),compareAndSet()。此外,讨论了ABA问题及其在CAS操作中的影响,并提出了AtomicStampedReference作为解决方案。

【悲观锁】Java 线程八锁

【线程】Java线程状态的转换

【悲观锁】Synchronized和ReentrantLock的区别

【线程方法】多线程下 wait、notify、park、unpark 和 await、signal 的区别

【内存】Java中的volatile

【设计模式-单例模式】Java 单例模式双重校验锁变量

【CAS-乐观锁】AtomicInteger

【乐观锁】AtomicReference

【设计模式-享元模式】Java 享元模式自定义连接池

【线程池】自定义线程池

【线程池】ThreadPoolExecutor 线程池

【线程池】Executeror 构建线程池的方法

【线程池】ThreadPoolExecutor 的拒绝策略

【悲观锁】主要的 AQS 方法

【悲观锁】ReentrantReadWriteLock

【同步工具】StampedLock

【同步工具】CountDownLatch

【同步工具】CyclicBarrier和CountDownLatch的区别

线程安全集合类

LinkedBlockingQueue 怎么实现的线程安全

AtomicReference 是 Java 中 java.util.concurrent.atomic 包下提供的原子引用类。它用于在多线程环境下原子性地更新引用类型的对象。与 AtomicInteger 类似,AtomicReference 的实现也基于 CAS(Compare-And-Swap)操作

1、AtomicReference 的主要方法:

1、get() 获取当前引用的值。

AtomicReference<String> atomicRef = new AtomicReference<>("Initial Value");
String value = atomicRef.get();

2、set(newValue) 设置引用的新值。

AtomicReference<String> atomicRef = new AtomicReference<>("Initial Value");
atomicRef.set("New Value");

3、getAndSet(newValue) 获取当前引用的值,并设置新值。

AtomicReference<String> atomicRef = new AtomicReference<>("Initial Value");
String oldValue = atomicRef.getAndSet("New Value");

4、compareAndSet(expectedValue, newValue) 比较当前引用的值是否等于期望值,如果相等则设置新值。

AtomicReference<String> atomicRef = new AtomicReference<>("Initial Value");
boolean success = atomicRef.compareAndSet("Initial Value", "New Value");

示例

import java.util.concurrent.atomic.AtomicReference;

public class AtomicReferenceExample {
    public static void main(String[] args) {
        AtomicReference<String> atomicRef = new AtomicReference<>("Initial Value");

        // 获取当前值
        String currentValue = atomicRef.get();
        System.out.println("Current Value: " + currentValue);

        // 设置新值
        atomicRef.set("New Value");
        System.out.println("Updated Value: " + atomicRef.get());

        // 获取并设置新值
        String oldValue = atomicRef.getAndSet("Another Value");
        System.out.println("Old Value: " + oldValue);
        System.out.println("Current Value: " + atomicRef.get());

        // 比较并设置新值
        boolean success = atomicRef.compareAndSet("Another Value", "Success");
        System.out.println("CAS Operation Successful? " + success);
        System.out.println("Current Value: " + atomicRef.get());
    }
}

2、原子引用ABA问题

"ABA 问题" 是在使用 CAS等原子操作时可能出现的一种情况。具体来说,它涉及到一个变量从 A 变成 B,然后再变回 A 的过程。

假设有线程 T1 在执行 CAS 操作时,读取了一个共享变量的值为 A,然后线程 T2 将这个变量的值修改为 B,最后线程 T2再将其修改回 A。在 T1 执行 CAS 操作时,由于变量的值仍然是 A,最终CAS 操作成功,但实际上中间发生了其他线程的干扰,使得变量的含义发生了变化。

这个问题可能导致程序在使用 CAS 操作进行数据同步时出现错误,因为 CAS 只能判断变量的当前值是否与预期值相等,而无法判断变量在操作过程中是否发生了变化。

解决ABA问题的方法1:

AtomicStampedReference 是 Java 中 java.util.concurrent.atomic 包下提供的原子引用类之一。它通过引入一个“标记”(stamp)来解决 CAS 操作中的 ABA 问题。每次更新引用时,同时也会更新对应的标记,从而增加了对变量状态的判断。

import java.util.concurrent.atomic.AtomicStampedReference;

public class AtomicStampedReferenceExample {
    public static void main(String[] args) {
        AtomicStampedReference<String> atomicRef = new AtomicStampedReference<>("Initial Value", 0);

        // 获取当前值和标记
        String currentValue = atomicRef.getReference();
        int currentStamp = atomicRef.getStamp();
        System.out.println("Current Value: " + currentValue);
        System.out.println("Current Stamp: " + currentStamp);

        // 设置新值和新标记
        atomicRef.set("New Value", 1);
        System.out.println("Updated Value: " + atomicRef.getReference());
        System.out.println("Updated Stamp: " + atomicRef.getStamp());

           // 尝试将引用的值从 "Initial Value" 更新为 "New Value",版本戳为 0
        boolean success = atomicRef.compareAndSet("Initial Value", "New Value", 0, 1);
        System.out.println("CAS Operation Successful? " + success);
        System.out.println("Current Value: " + atomicRef.getReference());
        System.out.println("Current Stamp: " + atomicRef.getStamp());
    }
}

解决ABA问题的方法2:

使用 AtomicMarkableReference 解决 ABA 问题,适用于你只想知道这个数据改没改,并不care改了几次。

import java.util.concurrent.atomic.AtomicMarkableReference;

public class AtomicMarkableReferenceExample {
    public static void main(String[] args) {
        // 创建一个 AtomicMarkableReference,初始引用为 0,标记位为 false
        AtomicMarkableReference<Integer> atomicRef = new AtomicMarkableReference<>(0, false);
        
        // 线程1:尝试更新引用值
        Thread t1 = new Thread(() -> {
            Integer oldValue = atomicRef.getReference();
            boolean oldMark = atomicRef.isMarked();
            System.out.println("线程1初始值: " + oldValue + ", 标记位: " + oldMark);
            
            // 线程1将引用值修改为 1,标记位保持不变
            boolean updated = atomicRef.compareAndSet(oldValue, 1, oldMark, oldMark);
            System.out.println("线程1更新引用值: " + updated);
        });
        
        // 线程2:尝试在其他线程更改引用时检查它
        Thread t2 = new Thread(() -> {
            Integer oldValue = atomicRef.getReference();
            boolean oldMark = atomicRef.isMarked();
            System.out.println("线程2初始值: " + oldValue + ", 标记位: " + oldMark);
            
            // 线程2将引用值修改为 2,标记位为 true
            boolean updated = atomicRef.compareAndSet(oldValue, 2, oldMark, true);
            System.out.println("线程2更新引用值: " + updated);
        });
        
        // 启动线程
        t1.start();
        t2.start();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值