解决ABA问题,原子引用

解决ABA问题,原子引用

整体思想是乐观锁。

一般的实现乐观锁的方式就是记录数据版本。

img 线程在提交前,根据版本号来判断是否冲突。

看代码:

package com.cc.cas;

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

public class CASDemo {

    static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(1,1);

    public static void main(String[] args) {

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

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

            System.out.println(atomicStampedReference.compareAndSet(1, 2,
                    atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1));
            System.out.println("A2=>" + atomicStampedReference.getStamp());

            System.out.println(atomicStampedReference.compareAndSet(2, 1,
                    atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1));
            System.out.println("A3=>" + atomicStampedReference.getStamp());

        },"A").start();


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

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

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

            System.out.println("B2=>" + atomicStampedReference.getStamp());

        },"B").start();

    }
}

运行结果:

A1=>1
B1=>1
true
A2=>2
true
A3=>3
false
B2=>3

可看到最后false,B2获得的版本号为3了,通过版本号知道值被线程A改过。

这里要注意一个问题:

AtomicStampedReference,如果泛型是包装类,注意对象的引用。

Integer 使用了对象缓存机制,默认范围是 -128 ~ 127 ,推荐使用静态工厂方法 valueOf 获取对象实例,而不是new,因为 valueOf 使用缓存,而 new 一定会创建新的对象分配新的内存空间;
在这里插入图片描述

在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时,才能确认状态确实发生了改变。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值