原子引用解决ABA问题

原子引用

首先先来了解这是干什么的,是为了解决ABA问题,ABA问题又是什么问题呢?看下面解释。

ABA问题用俗话来说,也就是狸猫换太子的问题,在多个线程运行下,上一个线程执行完将值返回给主存的时候,被另外一个线程更改回了原先的数据,导致下一个线程不知道线程被更改的问题!

package com.liu.cas;

import java.util.concurrent.atomic.AtomicInteger;

public class CASDemo01 {
    //cas:compareAndSet:比较并交换
    public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(2022); //底层用的cas
        //public final boolean compareAndSet(int expect, int update)
        //如果期望的值达到了就更新,否则不更新,CAS是CPU的并发原语!

        //对于写的sql:利用乐观锁解决问题:要知道谁动了线程!
        //=======捣乱的线程=========
        System.out.println(atomicInteger.compareAndSet(2022, 2023));
        System.out.println(atomicInteger.get());

        System.out.println(atomicInteger.compareAndSet(2023, 2022));
        System.out.println(atomicInteger.get());

        //=======捣乱的线程=========
        System.out.println(atomicInteger.compareAndSet(2022, 6666));
        System.out.println(atomicInteger.get());
    }

}

在了解ABA问题后,我们需要了解两个锁的概念,乐观锁和悲观锁的区别!见

(36条消息) Java中关于各种锁的概念_牛牛的Java学习之旅的博客-优快云博客

利用带版本号的原子引用解决ABA问题:知道谁动了线程,修改了数据,AtomicStampedReference() 带时间戳的,对应的思想是乐观锁

避坑:

Integer使用了对象缓存机制,默认范围是-128-127,推荐使用静态工厂方法valueOf获取对象实例,而不是new,因为valueOf使用缓存,而new一定会创建新的对象分配新的内存空间,超过这个区间的所有数据都会在堆上产生,不会复用对象

package com.liu.cas;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicStampedReference;

public class CASDemo02 {

    public static void main(String[] args) {
        //注意:如果泛型是包装类,注意对象的引用问题,因为是对象缓存机制,超过一定访问再new的话会新分配空间地址
        //正常在业务操作,这里引用的都是一个对象
        AtomicStampedReference<Integer> atomicInteger = new AtomicStampedReference<>(1, 1);

        new Thread(()->{
            int stamp = atomicInteger.getStamp();//获得版本号
            System.out.println("a1=>"+stamp);

            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //下面这一段代码跟乐观锁里面的version+1版本号操作一样
            System.out.println(atomicInteger.compareAndSet(1, 2,
                    atomicInteger.getStamp(), atomicInteger.getStamp() + 1));

            System.out.println("a2=>"+atomicInteger.getStamp());

            System.out.println(atomicInteger.compareAndSet(2, 1,
                    atomicInteger.getStamp(), atomicInteger.getStamp() + 1));

            System.out.println("a3=>"+atomicInteger.getStamp());
        },"a").start();

        //与乐观锁的原理相同,由于中间修改过了线程,导致正常的线程不能修改,返回false
        new Thread(()->{
            int stamp = atomicInteger.getStamp();//版本号获取
            System.out.println("b1=>"+stamp);

            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(atomicInteger.compareAndSet(1, 6, stamp, stamp + 1));

            System.out.println("b2=>"+atomicInteger.getStamp());
        },"b").start();
    }
}
C++中,ABA问题通常出现在基于引用计数的循环依赖场景,比如在多线程环境中对共享资源进行并发访问时可能会遇到数据竞争。ABA问题是当两个线程分别改变了A状态到B状态再到A状态,由于更新顺序不确定,外部观察者无法确定两次A状态变化是否实际上是同一个操作。 要解决这个问题,可以采用版本控制、弱引用、原子标记等技术。这里提供一个简单的使用std::atomic标志的例子: ```cpp #include <atomic> #include <thread> // 定义状态枚举和共享变量 enum class State { A, B }; std::atomic<State> shared_state{State::A}; std::atomic<bool> is_changed(false); // 标记状态是否有变化 void change_state(State new_state) { // 使用原子操作保证线程安全 while (true) { if (!is_changed.load()) { // 如果当前没有变化 if (shared_state.compare_exchange_strong( &shared_state, new_state, std::memory_order_release, std::memory_order_acquire)) { // 成功交换并设置标记 is_changed.store(true, std::memory_order_release); break; } } else { // 如果有变化,等待前一次更改完成 std::this_thread::yield(); } } } int main() { std::thread t1(change_state, State::B); std::thread t2(change_state, State::A); t1.join(); t2.join(); if (shared_state == State::A && !is_changed.load()) { std::cout << "No ABA issue detected" << std::endl; } return 0; } ``` 在这个例子中,`change_state`函数尝试原子地改变状态,并设置`is_changed`标志。如果其他线程正在修改状态,它会等待直到结束。外部检查时,只有在状态和标记都表明未发生ABA时,才能确认状态确实发生了改变。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值