CAS的ABA问题

    技术2026-03-18  3

    CAS的ABA问题 1.什么是ABA问题 CAS算法实现的一个重要前提就是需要取出内存中的某时刻的数据并在当前时刻比较并替换,那么在这个时间差之内会导致数据的变化。 例如有一个线程T1从内存地址X中取出A,这时另一个线程T2也从内存地址X中取出A,并且线程T2进行了一系列操作将值改变成B,写回主物理内存。然后线程T2又将内存地址为X的数据变为A,这个时候线程T1进行了CAS操作发现内存中仍然是A,这时线程T1进行CAS操作成功。尽管线程T1的CAS操作成功,但并不代表这个过程就没有问题,这就是ABA问题。 2.如何解决ABA问题 (1).原子引用–AtomicReference

    package com.example.demo; import jdk.nashorn.internal.objects.annotations.Getter; import java.util.concurrent.atomic.AtomicReference; /** * Created by Administrator on 2020/7/4. * * @author qtx */ class People { String userName; int age; public People() { } public People(String userName, int age) { this.userName = userName; this.age = age; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "People{" + "userName='" + userName + '\'' + ", age=" + age + '}'; } } /** * @author qtx */ public class AtomicReferenceDemo { public static void main(String[] args) { AtomicReference<People> peopleAtomicReference = new AtomicReference<>(); People p1 = new People("张三", 25); People p2 = new People("李四", 30); //给默认值到主物理内存 peopleAtomicReference.set(p1); System.out.println(peopleAtomicReference.compareAndSet(p1, p2) + "\t" + peopleAtomicReference.get().toString()); System.out.println(peopleAtomicReference.compareAndSet(p1, p2) + "\t" + peopleAtomicReference.get().toString()); } }

    (2).时间戳的原子引用–AtomicStampedReference

    package com.example.demo; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicStampedReference; /** * Created by Administrator on 2020/7/4. * * @author qtx */ public class ABADemo { static AtomicReference<Integer> atomicReference = new AtomicReference<>(50); static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(50, 1); public static void main(String[] args) { new Thread(() -> { atomicReference.compareAndSet(50, 51); atomicReference.compareAndSet(51, 50); }).start(); new Thread(() -> { try { //保证线程1必须完成一次ABA过程 TimeUnit.SECONDS.sleep(2); } catch (Exception e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "\t" + atomicReference.compareAndSet(50, 1024) + "\t" + atomicReference.get()); ; }).start(); System.out.println("-------------ABA解决方案------------------"); new Thread(() -> { int stamp = atomicStampedReference.getStamp(); System.out.println(Thread.currentThread().getName() + "\t线程3的第一次版本号:" + stamp); try { //保证线程2和线程3取到的是同一个版本号1 TimeUnit.SECONDS.sleep(2); } catch (Exception e) { e.printStackTrace(); } atomicStampedReference.compareAndSet(50, 51, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1); System.out.println(Thread.currentThread().getName() + "\t线程3的第二次版本号:" + atomicStampedReference.getStamp()); atomicStampedReference.compareAndSet(51, 50, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1); System.out.println(Thread.currentThread().getName() + "\t线程3的第三次版本号:" + atomicStampedReference.getStamp()); }).start(); new Thread(() -> { int stamp = atomicStampedReference.getStamp(); System.out.println(Thread.currentThread().getName() + "\t线程4的最开始取到的版本号:" + stamp); try { //保证线程2和线程3取到的是同一个版本号1 TimeUnit.SECONDS.sleep(5); } catch (Exception e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "\t线程4:" + atomicStampedReference.compareAndSet(50, 1024, stamp, stamp + 1) + "\t线程4取到的实际的真实的当前版本号:" + atomicStampedReference.getStamp()); System.out.println(Thread.currentThread().getName() + "\t线程4当前的真实值:" + atomicStampedReference.getReference()); }).start(); } }
    Processed: 0.010, SQL: 9