原子类、原子更新引用

1,172 阅读2分钟

引言:更多相关请看 JAVA并发编程系列

ABA问题

CAsS算法实现一个重要前提需要取出内存中某时刻的数据并在当下时刻比较并替换,那么在这个时间差类会导致数据的变化。比如说一个线程one从内存位置v中取出A,这时候另一个线程two也从内存中取出A,并且线程two进行了一些操作将值变成了B,然后线程two又将V位置的数据变成A,这时候线程one进行CAS操作发现内存中仍然是A,然后线程one操作成功。尽管线程one的CAS操作成功,但是不代表这个过程就是没有问题的。

原子引用AtomicReference

包java.util.concurrent.atomic下

案例:

@Data
@AllArgsConstructor
@NoArgsConstructor
class User {
    private String name;
    private int age;
}

class AtomicReferenceDemo {
    public static void main(String[] args) {
        User root = new User("root", 22);
        User admin = new User("admin", 22);
        AtomicReference<User> userAtomicReference = new AtomicReference<>();
        userAtomicReference.set(root);
        // true	User(name=admin, age=22)
        System.out.println(userAtomicReference.compareAndSet(root, admin) + "\t" + userAtomicReference.get().toString());
        // false	User(name=admin, age=22)
        System.out.println(userAtomicReference.compareAndSet(root, admin) + "\t" + userAtomicReference.get().toString());
    }
}

时间戳原子引用AtomicStampedReference

解决ABA问题:
AtomicStampedReference类的compareAndSet方法

expectedReference期望值、newReference更新的值、expectedStamp期望版本号、newStamp更新版本号。 有且仅有线程和内存中的expectedReference期望值、expectedStamp期望版本号都相等时,才允许修改内存中的值和版本号。避免ABA问题 案例:

class ABADemo {
    private static AtomicReference<Integer> atomicReference = new AtomicReference<>(100);
    private static AtomicStampedReference<Integer> stampedReference = new AtomicStampedReference<>(100, 1);

    public static void main(String[] args) {
        System.out.println("=================ABA问题产生=================");
        new Thread(() -> {
            // 完成ABA
            atomicReference.compareAndSet(100, 101);
            atomicReference.compareAndSet(101, 100);
        }, "t1").start();
        new Thread(() -> {
            // 先暂停1秒 保证完成ABA
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(atomicReference.compareAndSet(100, 2019) + "\t" + atomicReference.get());
        }, "t2").start();
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("=================ABA问题解决=================");
        int stamp = stampedReference.getStamp();// 初始版本号
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName()+"初始值:"+stampedReference.getReference() + " 版本号:"+stamp);
            stampedReference.compareAndSet(100, 101, stamp, stamp + 1);
            stampedReference.compareAndSet(101, 100, stampedReference.getStamp(), stampedReference.getStamp() + 1);
            System.out.println(Thread.currentThread().getName()+"最终值:"+stampedReference.getReference() + " 版本号:"+stampedReference.getStamp());
        }, "t3").start();
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName()+"初始值:"+stampedReference.getReference() + " 版本号:"+stamp);
            // 先暂停1秒 保证完成ABA
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"修改状态:"+stampedReference.compareAndSet(100, 2019, stamp,stamp+1));
            System.out.println(Thread.currentThread().getName()+"ABA最终值:"+stampedReference.getReference() + " ABA最终版本号:"+stampedReference.getStamp());
        }, "t4").start();
    }
}

效果: