突击并发编程JUC系列演示代码地址:
https://github.com/mtcarpenter/JavaTutorial

他来了,他来了,他带着 ABA 问题走来了,小伙伴们,大家好,咱们又见面了,突击并发编程 JUC 系列实战原子更新数组类马上就要发车了。

字段类型

如果须要原子地更新某个类里的某个字段时,就须要应用原子更新字段类,Atomic包提供了以下3个类进行原子字段更新。

小试牛刀

AtomicIntegerFieldUpdater案例演示

原子地更新整形字段类,还是那个糊涂少年,在批改本人的票数。
老师类如下:

public class Teacher {    /**     * 老师名称     */    public volatile String name;    /**     * 学生投票数     */    public volatile int ticketNum;    public Teacher(String name, int ticketNum) {        this.name = name;        this.ticketNum = ticketNum;    }    public String getName() {        return name;    }    public int getTicketNum() {        return ticketNum;    }}
public class AtomicExample8 {    private static AtomicIntegerFieldUpdater<Teacher> integerFieldUpdater = AtomicIntegerFieldUpdater.newUpdater(Teacher.class, "ticketNum");    public static void main(String[] args) {        // 设置糊涂少年 180票        Teacher teacher = new Teacher("糊涂少年", 180);        // 180        System.out.println("getAndIncrement = " + integerFieldUpdater.getAndIncrement(teacher));               System.out.println("get=" + integerFieldUpdater.get(teacher));    }}//getAndIncrement = 180//get=181

要想原子地更新字段类须要两步。

  • 第一步,因为原子更新字段类都是抽象类,每次应用的时候必须应用静态方法newUpdater()创立一个更新器,并且须要设置想要更新的类和属性。
  • 第二步,更新类的字段(属性)必须应用public volatile修饰符。

AtomicIntegerFieldUpdaterAtomicIntegerFieldUpdater 办法根本相似,办法getAndIncrement()getAndDecrement()getAndAdd()等办法,跟后面的 Atomiclong实现也根本类同。

AtomicStampedReference 案例演示

CAS 后面咱们都晓得,比拟替换,要更新的变量和预期值相等,则批改为预期预期值,否则批改失败。所以 CAS 就产生了经典的 ABA 问题,什么是ABA 问题呢?比方一个值原来是A,变成了B,起初又变成了A,那么CAS查看时会发现它的值没有发生变化,然而实际上却是产生了变动的。

加深印象

大学选课小伙伴应该深有体会,一到选课零碎卡,解体重启还在卡,多人选课多人卡,除了领取都会卡。当初有一门网红网课,课程人数限度为 100 人,这门课程相当火爆,选课零碎开启后,半分钟这门课程就达到了 99 人,还残余1 个名额。学生 1学生 2同时进入零碎,并点击了该课程抉择课程按钮,每一个名额都有一个相应的版本号进行管制,学生 2 在弹框呈现的时候校园网忽然断了,学生 1 就轻松选到了课程,然而学生1 发现心仪的女生没有选到此课程,就退掉了此课程,学生 2 网络好了 ,界面也呈现尽管还剩下一个名额,然而已被学生 1 操作过,学生 2 拿出上次的版本号,曾经无奈抉择课程。

public class AtomicExample9 {    private static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(99, 1);    public static void main(String[] args) {        Thread student1 = new Thread(() -> {            int stamp = atomicStampedReference.getStamp();            System.out.println(Thread.currentThread().getName() + "---首次 stamp: " + stamp);            atomicStampedReference.compareAndSet(99, 100,                    atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);            System.out.println(Thread.currentThread().getName() + "---第二次 stamp: " + atomicStampedReference.getStamp());            atomicStampedReference.compareAndSet(100, 99,                    atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);            System.out.println(Thread.currentThread().getName() + "---第三次 stamp: " + atomicStampedReference.getStamp());        }, "student1");        Thread student2 = new Thread(() -> {            int stamp = atomicStampedReference.getStamp();            System.out.println(Thread.currentThread().getName() + "---第一次 stamp: " + stamp);            try {                System.out.println(Thread.currentThread().getName() + "---你的校园网正在尝试从新连贯......");                TimeUnit.SECONDS.sleep(1);            } catch (InterruptedException e) {                e.printStackTrace();            }            boolean result = atomicStampedReference.compareAndSet(99, 100,                    stamp, stamp + 1);            System.out.println(Thread.currentThread().getName() + "---批改胜利与否:" + result + "  以后 stamp:" + atomicStampedReference.getStamp());            System.out.println(Thread.currentThread().getName() + "---以后课程已选人数:" + atomicStampedReference.getReference());        }, "student2");        student1.start();        student2.start();    }}
student1---首次 stamp: 1student1---第二次 stamp: 2student1---第三次 stamp: 3student2---第一次 stamp: 3student2---你的校园网正在尝试从新连贯......student2---批改胜利与否:true  以后 stamp:4student2---以后课程已选人数:100

总结

本章简略了介绍了 AtomicIntegerFieldUpdater 原子的更新某一个字段,AtomicStampedReference 能够用于解决JUC中的 ABA问题,比照前一个章节 AtomicStampedReference 只有 truefalse两种抉择。在并发中如果两个版本号一直地切换,依然不能很好地解决 ABA 问题,只是从某种程度升高了ABA事件产生。而应用 AtomicStampedReference 就能够防止这样的问题。


欢送关注公众号 山间木匠 , 我是小春哥,从事 Java 后端开发,会一点前端、通过继续输入系列技术文章与文会友,如果本文能为您提供帮忙,欢送大家关注、 点赞、分享反对,_咱们下期再见!