专栏首页JVMGCAtomicStampedReference解决CAS的ABA问题
原创

AtomicStampedReference解决CAS的ABA问题

AtomicStampReference

解决CASABA问题

什么是ABA

ABA问题:指CAS操作的时候,线程将某个变量值由A修改为B,但是又改回了A,其他线程发现A并未改变,于是CAS将进行值交换操作,实际上该值已经被改变过,这与CAS的核心思想是不符合的

ABA解决方案

每次变量更新的时候,把变量的版本号进行更新,如果某变量被某个线程修改过,那么版本号一定会递增更新,从而解决ABA问题

AtomicReference 演示ABA问题

package com.keytech.task;


import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;

public class AtomicIntegerTest {
    private static AtomicReference<Integer> count=new AtomicReference<>(10);
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();

        executorService.execute(()->{
            boolean b = count.compareAndSet(10, 12);
            if(b){
                System.out.println(Thread.currentThread().getName()+"修改成功count="+count.get());
            }
            boolean c =count.compareAndSet(12, 10);
            if(c){
                System.out.println(Thread.currentThread().getName()+"修改成功count="+count.get());
            }
        });

        executorService.execute(()->{
            boolean b = count.compareAndSet(10, 100);
            if(b){
                System.out.println(Thread.currentThread().getName()+"修改成功count="+count.get());
            }

        });

        executorService.shutdown();

    }
}
//pool-1-thread-1修改成功count=12
//pool-1-thread-1修改成功count=10
//pool-1-thread-2修改成功count=100

pool-1-thread-1count由10修改成12,又将count从12改成10。 pool-1-thread-2count从10成功改成100。出现了ABA的问题。

AtomicStampedReference解决ABA的问题

以计数器的实现为例,计数器通常用来统计在线人数,在线+1,离线-1,是ABA的典型场景。

package com.keytech.task;

import java.util.concurrent.atomic.AtomicStampedReference;


public class CounterTest {
    private AtomicStampedReference<Integer> count=new AtomicStampedReference<Integer>(0,0);
    public int getCount(){
        return count.getReference();
    }
    public int increment(){
        int[] stamp=new int[1];
        while (true){
            Integer value = count.get(stamp);
            int newValue=value+1;
            boolean b = count.compareAndSet(value, newValue, stamp[0], stamp[0] + 1);
            if(b){
                return newValue;
            }

        }
    }

    public int decrement(){
        int[] stamp=new int[1];
        while(true){
            Integer value=count.get(stamp);
            int newValue=value-1;
            boolean b = count.compareAndSet(value, newValue, stamp[0], stamp[0] + 1);
            if(b){
                return newValue;
            }
        }
    }
}

调用计数器

package com.keytech.task;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;

public class AtomicIntegerTest {
    public static void main(String[] args) {


        ExecutorService executorService = Executors.newCachedThreadPool();
        Semaphore semaphore=new Semaphore(200);
        CounterTest counterTest=new CounterTest();

        for (int i = 0; i < 5000; i++) {
            executorService.execute(()->{
                try{
                    semaphore.acquire();
                    counterTest.increment();
                    semaphore.release();
                }catch (Exception e){
                    e.printStackTrace();
                }

            });
            executorService.execute(()->{
                try{
                    semaphore.acquire();
                    counterTest.decrement();
                    semaphore.release();
                }catch (Exception e){
                    e.printStackTrace();
                }

            });
        }

        executorService.shutdown();
        System.out.println(counterTest.getCount());

    }
}

//输出0

AtomicBoolean保证高并发下只执行一次

package com.keytech.task;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicBoolean;


public class AtomicBooleanTest {
    private static AtomicBoolean isHappen=new AtomicBoolean(false);
    public static int clientTotal=5000;
    public static int threadTotal=200;

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        Semaphore semaphore=new Semaphore(threadTotal);
        for (int i = 0; i < clientTotal; i++) {
            executorService.execute(()->{
                try {
                    semaphore.acquire();
                    update();
                    semaphore.release();
                }catch (Exception e){
                    e.printStackTrace();
                }
            });
        }

        executorService.shutdown();
    }
    private static void update(){
        if(isHappen.compareAndSet(false, true)){
            System.out.println("只执行一次");
        }
    }
}
//只执行一次
wx.jpg

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • AtomicStampedReference是怎样解决CAS的ABA问题

    但凡对Java有一点深入就会知道 CAS,即 compareAndSwap。在Java中使用 Unsafe 类提供的native方法可以直接操作内存,其中就有对...

    龟仙老人
  • AtomicStampedReference 源码分析

    AtomicStampedReference 是对 AtomicReference 的一个补充,解决了在 CAS 场景下 ABA 的问题

    itliusir
  • 死磕Java并发:深入分析CAS

    CAS,Compare And Swap,即比较并交换。Doug lea大神在同步组件中大量使用CAS技术鬼斧神工地实现了Java多线程的并发操作。整个AQS同...

    程序猿DD
  • 【死磕Java并发】—- 深入分析CAS

    CAS,Compare And Swap,即比较并交换。Doug lea大神在同步组件中大量使用CAS技术鬼斧神工地实现了Java多线程的并发操作。整个AQS同...

    芋道源码
  • 【死磕Java并发】—-深入分析CAS

    CAS,Compare And Swap,即比较并交换。Doug lea大神在同步组件中大量使用CAS技术鬼斧神工地实现了Java多线程的并发操作。整个AQS同...

    用户1655470
  • 死磕 java并发包之AtomicStampedReference源码分析

    AtomicStampedReference是java并发包下提供的一个原子类,它能解决其它原子类无法解决的ABA问题。

    彤哥
  • JUC 多线程 CAS 算法

    解释:一个线程在使用atomicInteger原子变量进行修改值的操作中,底层的CAS算法会拿自己工作空间的值去和主内存空间的值去比较,如果主内存值和期望数值5...

    万能青年
  • CAS 原子操作

      有时候面试官面试问你的时候,会问,谈谈你对CAS的理解,这时应该有很多人,就会比较懵,当然,我也会比较懵,当然我和很多人的懵不同,很多人可能,并不知道CAS...

    后端码匠
  • CAS 原子操作

    有时候面试官面试问你的时候,会问,谈谈你对CAS的理解,这时应该有很多人,就会比较懵,当然,我也会比较懵,当然我和很多人的懵不同,很多人可能,并不知道CAS是一...

    彼岸舞
  • 引用类型原子类

    基本类型原子类只能更新一个变量,如果需要原子更新多个变量,需要使用 引用类型原子类。

    黑洞代码
  • 2020-10-16:CAS知道么?底层实现? 会引发什么问题?如何解决ABA问题?

    CAS 底层实现主要依靠的cmpxchg是 CPU 指令级的操作,只有一步原子操作,所以非常快。它本身的性能瓶颈主要来自于:多核环境下,上次执行 CAS 更新的...

    福大大架构师每日一题
  • Java面试之CAS

    功能:判断内存某个位置的L值是否为预期值,如果是则更改为新的值,这个过程是原子的。

    乐心湖
  • Java并发基础:了解无锁CAS就从源码分析

    CAS的全称为Compare And Swap,直译就是比较交换。是一条CPU的原子指令,其作用是让CPU先进行比较两个值是否相等,然后原子地更新某个位置的值,...

    良月柒
  • Java并发必知必会第三弹:用积木讲解ABA原理 |老婆居然又听懂了!

    上一节我们讲了程序员深夜惨遭老婆鄙视,原因竟是CAS原理太简单?,留了一个彩蛋给大家,ABA问题是怎么出现的,为什么不是AAB拖拉机,AAA金花,4个A炸弹 ?...

    悟空聊架构
  • Java并发编程之CAS第三篇-CAS的缺点

    通过前两篇的文章介绍,我们知道了CAS是什么以及查看源码了解CAS原理。那么在多线程并发环境中,的缺点是什么呢?这篇文章我们就来讨论讨论

    凯哥Java
  • java 中的CAS与ABA问题

    属于悲观锁,有共享资源,需要加锁时,会以独占锁的方式导致其它需要获取锁才能执行的线程挂起,等待持有锁的钱程释放锁。传统的关系型数据库里边就用到了很多这种锁机制,...

    开发架构二三事
  • 传说中的并发编程ABA问题

    什么是ABA问题 ABA并不是一个缩写,更像是一个形象的描述。ABA问题出现在多线程或多进程计算环境中。 首先描述ABA。假设两个线程T1和T2访问同一个变量V...

    小柒2012
  • "聊胜于无",浅析Java中的原子操作Unsafe类

    Java放弃了指针,获得了更高的安全性和内存自动清理的能力。但是,它还是在一个角落里提供了类似于指针的功能,那就是sun.misc.Unsafe类,利用这个类,...

    JavaEdge
  • Java并发:了解无锁CAS就从源码分析

    CAS的全称为Compare And Swap,直译就是比较交换。是一条CPU的原子指令,其作用是让CPU先进行比较两个值是否相等,然后原子地更新某个位置的值,...

    搜云库技术团队

扫码关注云+社区

领取腾讯云代金券