2019年互联网面试题第二季(1.3)

一.JUC多线程及并发包

1.3.原子类AtomicInteger的ABA问题谈谈?原子更新引用知道吗

ABA问题分析

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

ABA问题: 狸猫换太子, 在中途的时候 值被更换了,然后又换回来了

A—>B—->A 没人发现!

当线程A操作资源类的时候,访问资源类是时候假设为A,然后他就去sleep了,这个时候线程B来操作了,资源类从A变成了B,然后进行了一系列业务逻辑,然后线程C又来了,发现资源类现在成了B,是自己想要的,又操作一遍,这个时候线程C操作完以后,将资源类从B又变成A, 而线程A醒来傻傻的还没有发现。

如何解决ABA

  • 采用时间戳来解决原子引用问题或者版本号AtomicStampedReference类解决该方法

  • 采用 AtomicReference 操作 包装POJO对象

    AtomicReference 案例代码

class User{
    private int age;
    private String name;
    public User(int age,String name){
        this.age=age;
        this.name=name;
    }

}

public class AtomicInteger_1_3 {
    public static void main (String[] args) {
       User user1=new User(12, "zs");
       User user2=new User(18, "li");

        AtomicReference<User> userAtomicReference =new AtomicReference <>();
        userAtomicReference.set(user1);
        System.out.println(userAtomicReference.compareAndSet(user1, user2));
        System.out.println(userAtomicReference.compareAndSet(user1, user2));
    }
}

结果分析:

2019年互联网面试题第二季(1.3)


AtomicStampedReference 版本号Case

package com.ybzn._01.juc;

/**
 * @author Hugo
 * @time 2021/2/13
 */

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

/**
 * Description: ABA问题的解决 *
 */
public class ABADemo_1_3 {
    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(() -> {
            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问题的解决===");
        new Thread(() -> {
            int stamp = stampedReference.getStamp();
            System.out.println(Thread.currentThread().getName() + "\t 第1次版本号" + stamp + "\t值是" + stampedReference.getReference());            //暂停1秒钟t3线程
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            stampedReference.compareAndSet(100, 101, stampedReference.getStamp(), stampedReference.getStamp() + 1);
            System.out.println(Thread.currentThread().getName() + "\t 第2次版本号" + stampedReference.getStamp() + "\t值是" + stampedReference.getReference());
            stampedReference.compareAndSet(101, 100, stampedReference.getStamp(), stampedReference.getStamp() + 1);
            System.out.println(Thread.currentThread().getName() + "\t 第3次版本号" + stampedReference.getStamp() + "\t值是" + stampedReference.getReference());
        }, "t3").start();
        new Thread(() -> {
            int stamp = stampedReference.getStamp();
            System.out.println(Thread.currentThread().getName() + "\t 第1次版本号" + stamp + "\t值是" + stampedReference.getReference());            //保证线程3完成1次ABA
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            boolean result = stampedReference.compareAndSet(100, 2019, stamp, stamp + 1);
            System.out.println(Thread.currentThread().getName() + "\t 修改成功否" + result + "\t最新版本号" + stampedReference.getStamp());
            System.out.println("最新的值\t" + stampedReference.getReference());
        }, "t4").start();
    }
}

结果分析:

2019年互联网面试题第二季(1.3)

上一篇:Java并发编程之CAS第三篇-CAS的缺点及解决办法


下一篇:原子操作类的使用以及ABA问题的解决