其他分享
首页 > 其他分享> > ABA问题

ABA问题

作者:互联网

ABA问题

CAS --> UnSafe --> CAS底层思想 --> ABA -->原子引用更新 -->如何规避ABA问题

1.介绍

1.1图解

1.2演示

import java.util.concurrent.atomic.AtomicReference;

public class ABADemo {
    static AtomicReference<Integer> atomicReference= new AtomicReference<>(100);
    public static  void main(String[] args){
        new Thread(() ->{
            atomicReference.compareAndSet(100, 101);
            atomicReference.compareAndSet(101, 100);
        },"t1").start();
        new Thread(() ->{
            //暂停1s,保证t1完成了一次ABA操作
            try{
                TimeUnit.SECONDS.sleep(1);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            System.out.println( atomicReference.compareAndSet(100, 2019)+"\t"+atomicReference.get());

        },"t2").start();
    }
}

2. 如何解决ABA问题

2.1 原子引用

import java.util.concurrent.atomic.AtomicReference;
class User{
    String userName;
    int age;

    public User(String userName, int age) {
        this.userName = userName;
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "userName='" + userName + '\'' +
                ", age=" + age +
                '}';
    }
}
public class AtomicReferenceDemo {
    public static void main(String[] args){
        AtomicReference<User> atomicReference = new AtomicReference<>();
        User z3 = new User("z3",22);
        User l4 = new User("l4",25);
        atomicReference.set(z3);
        System.out.println(atomicReference.compareAndSet(z3, l4)+"\t"+atomicReference.get().toString());
        System.out.println(atomicReference.compareAndSet(z3, l4)+"\t"+atomicReference.get().toString());
    }
}

2.2时间戳原子引用

//AtomicStampeReference
public class ABADemo {
    static AtomicReference<Integer> atomicReference= new AtomicReference<>(100);
    static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<Integer>(100, 1);
    public static  void main(String[] args){
        new Thread(() ->{
            int stamp = atomicStampedReference.getStamp();
            System.out.println(Thread.currentThread().getName()+"\t第一次版本号"+stamp);
            try{
                TimeUnit.SECONDS.sleep(1);
            }catch (InterruptedException e){
                e.printStackTrace();}
            atomicStampedReference.compareAndSet(100,12,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1);
            System.out.println(Thread.currentThread().getName()+"\t第二次版本号"+atomicStampedReference.getStamp());
            System.out.println(Thread.currentThread().getName()+"\t当前值"+atomicStampedReference.getReference());
            System.out.println(atomicStampedReference.compareAndSet(12,100,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1));
            System.out.println(Thread.currentThread().getName()+"\t第三次版本号"+atomicStampedReference.getStamp());
        },"t3").start();
        new Thread(() ->{
            int stamp = atomicStampedReference.getStamp();
            System.out.println(Thread.currentThread().getName()+"\t第一次版本号"+stamp);
            try{
                TimeUnit.SECONDS.sleep(5);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            boolean result = atomicStampedReference.compareAndSet(100,101,stamp,stamp+1);
            System.out.println(Thread.currentThread().getName()+"\t修改"+result+"\t当前版本号"+atomicStampedReference.getStamp());
            System.out.println(Thread.currentThread().getName()+"\t当前值"+atomicStampedReference.getReference());
        },"t4").start();
    }
}

3.问题

  1. 当CAS传入的新值大于等于128的时候一直修改失败

    原因:Integer对-128~127间的数字有缓存,所以在此区间的current==expectedReference为true,当current>127,每次装箱将返回新的Integer对象,此时current!=expectedReference导致compareAndSet一直返回false。

标签:ABA,Thread,System,问题,println,atomicStampedReference,atomicReference,out
来源: https://www.cnblogs.com/ftfty/p/15915615.html