AtomicStampedReference、AtomicMarkableReference源码分析,解决cas ABA问题

2023-11-13

cas的ABA问题就是 假设初始值为A,线程3和线程1都获取到了初始值A,然后线程1将A改为了B,线程2将B又改回了A,这时候线程3做修改时,是感知不到这个值从A改为了B又改回了A的过程:

AtomicStampedReference 本质是有一个int 值作为版本号,每次更改前先取到这个int值的版本号,等到修改的时候,比较当前版本号与当前线程持有的版本号是否一致,如果一致,则进行修改,并将版本号+1(当然加多少或减多少都是可以自己定义的),在zookeeper中保持数据的一致性也是用的这种方式;

AtomicMarkableReference则是将一个boolean值作是否有更改的标记,本质就是它的版本号只有两个,true和false,修改的时候在这两个版本号之间来回切换,这样做并不能解决ABA的问题,只是会降低ABA问题发生的几率而已;

看下面这个例子里面有主要源码的解析:

[plain]  view plain  copy
  1. import java.util.concurrent.atomic.AtomicMarkableReference;  
  2. import java.util.concurrent.atomic.AtomicStampedReference;  
  3.   
  4. /**  
  5.  * 解决atomic类cas操作aba问题,解决方式是在更新时设置版本号的方式来解决,每次更新就要设置一个不一样的版本号,修改的时候,不但要比较值有没有变,还要比较版本号对不对,这个思想在zookeeper中也有体现;  
  6.  * @author Administrator  
  7.  *  
  8.  */  
  9. public class AtomicStampedReferenceTest {  
  10.   
  11.     public final static AtomicStampedReference<String> ATOMIC_REFERENCE = new AtomicStampedReference<String>("abc", 0);  
  12.   
  13.     /**  
  14.      *  
  15.     它里面只有一个成员变量,要做原子更新的对象会被封装为Pair对象,并赋值给pair;  
  16.     private volatile Pair<V> pair;  
  17.       
  18.     先看它的一个内部类Pair ,要进行原子操作的对象会被封装为Pair对象  
  19.     private static class Pair<T> {  
  20.         final T reference;     //要进行原子操作的对象  
  21.         final int stamp;       //当前的版本号  
  22.         private Pair(T reference, int stamp) {  
  23.             this.reference = reference;  
  24.             this.stamp = stamp;  
  25.         }  
  26.         static <T> Pair<T> of(T reference, int stamp) { //该静态方法会在AtomicStampedReference的构造方法中被调用,返回一个Pair对象;  
  27.             return new Pair<T>(reference, stamp);  
  28.         }  
  29.     }  
  30.     现在再看构造方法就明白了,就是将原子操作的对象封装为pair对象  
  31.     public AtomicStampedReference(V initialRef, int initialStamp) {  
  32.         pair = Pair.of(initialRef, initialStamp);  
  33.     }  
  34.              
  35.            获取版本号      
  36.            就是返回成员变量pair的stamp的值         
  37.     public int getStamp() {  
  38.         return pair.stamp;  
  39.     }  
  40.       
  41.             原子修改操作,四个参数分别是旧的对象,将要修改的新的对象,原始的版本号,新的版本号  
  42.             这个操作如果成功就会将expectedReference修改为newReference,将版本号expectedStamp修改为newStamp;  
  43.     public boolean compareAndSet(V   expectedReference,  
  44.                                  V   newReference,  
  45.                                  int expectedStamp,  
  46.                                  int newStamp) {  
  47.         Pair<V> current = pair;  
  48.           
  49.         return  
  50.             expectedReference == current.reference && expectedStamp == current.stamp //如果原子操作的对象没有更改,并且版本号也没有更改,   
  51.             &&  
  52.             (  
  53.                 (newReference == current.reference &&newStamp == current.stamp) //如果要修改的对象与就的对象相同,并且新的版本号也与旧的版本号相同,也就是重复操作,这时候什么也不干  
  54.                 ||  
  55.                 casPair(current, Pair.of(newReference, newStamp)) //cas操作,生成一个新的Pair对象,替换掉旧的,修改成功返回true,修改失败返回false;  
  56.              );  
  57.     }  
  58.      * @param args  
  59.      */  
  60.     public static void main1(String[] args) {  
  61.         for (int i = 0; i < 100; i++) {  
  62.             final int num = i;  
  63.             final int stamp = ATOMIC_REFERENCE.getStamp();  
  64.             new Thread() {  
  65.                 public void run() {  
  66.                     try {  
  67.                         Thread.sleep(Math.abs((int) (Math.random() * 100)));  
  68.                     } catch (InterruptedException e) {  
  69.                         e.printStackTrace();  
  70.                     }  
  71.                     if (ATOMIC_REFERENCE.compareAndSet("abc", "abc2", stamp, stamp + 1)) {  
  72.                         System.out.println("我是线程:" + num + ",我获得了锁进行了对象修改!");  
  73.                     }  
  74.                 }  
  75.             }.start();  
  76.         }  
  77.         new Thread() {  
  78.             public void run() {  
  79.                 int stamp = ATOMIC_REFERENCE.getStamp();  
  80.                 while (!ATOMIC_REFERENCE.compareAndSet("abc2", "abc", stamp, stamp + 1))  
  81.                     ;  
  82.                 System.out.println("已经改回为原始值!");  
  83.             }  
  84.         }.start();  
  85.     }  
  86.       
  87.       
  88.     /**AtomicMarkableReference 解决aba问题,注意,它并不能解决aba的问题 ,它是通过一个boolean来标记是否更改,本质就是只有true和false两种版本来回切换,只能降低aba问题发生的几率,并不能阻止aba问题的发生,看下面的例子**/  
  89.     public final static AtomicMarkableReference<String> ATOMIC_MARKABLE_REFERENCE = new AtomicMarkableReference<String>("abc" , false);  
  90.       
  91.     public static void main(String[] args){  
  92.         //假设以下操作由不同线程执行  
  93.         System.out.println("mark:"+ATOMIC_MARKABLE_REFERENCE.isMarked()); //线程1 获取到mark状态为false,原始值为“abc”  
  94.         boolean thread1 = ATOMIC_MARKABLE_REFERENCE.isMarked();  
  95.         System.out.println("mark:"+ATOMIC_MARKABLE_REFERENCE.isMarked()); //线程3获取到mark状态为false ,原始值为“abc”  
  96.         boolean thread2 = ATOMIC_MARKABLE_REFERENCE.isMarked();  
  97.         System.out.println("change result:"+ATOMIC_MARKABLE_REFERENCE.compareAndSet("abc", "abc2", thread1, !thread1)); //线程1 更改abc为abc2  
  98.           
  99.         System.out.println("mark:"+ATOMIC_MARKABLE_REFERENCE.isMarked()); //线程2获取到mark状态为true ,原始值为“abc2”  
  100.         boolean thread3 = ATOMIC_MARKABLE_REFERENCE.isMarked();  
  101.         System.out.println("change result:"+ATOMIC_MARKABLE_REFERENCE.compareAndSet("abc2", "abc", thread3, !thread3));//线程2 更改abc2为abc  
  102.           
  103.         System.out.println("change result:"+ATOMIC_MARKABLE_REFERENCE.compareAndSet("abc", "abc2", thread2, !thread2));//线程3更改abc为abc2;  
  104.         //按照上面的执行顺序,3此修改都修改成功了,线程1与线程2拿到的mark状态都是false,他俩要做的操作都是将“abc”更改为“abc2”, 只是线程2在线程1和线程3中间做了一次更改,最后线程2做操作的时候并没有感知到线程1与线程3的更改;  
  105.     }  
  106.       
  107. }  


版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zqz_zqz/article/details/68062568
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

AtomicStampedReference、AtomicMarkableReference源码分析,解决cas ABA问题 的相关文章

  • C++ CAS 操作

    C 43 43 中的 CAS 操作用于操作原子变量 xff0c 它是 atomic lt T gt 的成员函数 span class token macro property span class token directive hash
  • cas-overlay-template 搭建单点登录服务端

    1 先下载overlay template的源码 git clone https github com apereo cas overlay template git 切换到5 3的分支 2 编译的坑 需要下载cas server weba
  • cas + tomcat 配置步骤详细笔记(一)

    首先需要准备资源如下 xff1a cas server 4 0 0 release zip xff0c cas client 2 0 11 zip xff0c apache tomcat 6 0 29 下面操作在dos下操作 xff08 开
  • 数据库锁机制和CAS概念

    这个作者介绍比较清晰 https www cnblogs com X knight p 10669934 html 64 勋爵
  • cas服务器连接数据库

    进行数据库的连接 xff0c 必须要导入一些必要的包 xff0c 比如数据库驱动 xff0c mysql连接等包 xff0c 这些maven依赖都能在网上找到 1 找到cas overlay template 5 3文件夹下的pom文件 x
  • CAS方式实现单点登录

    单点登录 xff0c 英文是 Single Sign On xff0c 缩写为 SSO 多个站点 192 168 1 20X 共用一台认证授权服务器 192 168 1 110 xff0c 用户数据库和认证授权模块共用 用户经由其中任何一个
  • 搭建Cas服务

    环境要求 JDK 1 8CAS 5 3tomcat 9 1 cas项目下载地址 xff1a https github com apereo cas overlay template tree 5 3 2 使用idea导入cas overla
  • cas服务端动态servers

    一 什么是servers cas的分为服务端和客户端 xff0c 如果客户端要使用cas需要把自己的域名或ip注册到cas服务端才可以使用 默认的servers为静态的 src main resources services HTTPSan
  • cas 配置相关

    默认配置 span class token comment span span class token comment CAS Cloud Bus Configuration span span class token comment sp
  • 经典的ABA问题与解决方法

    1 AbA问题的产生 要了解什么是ABA问题 首先我们来通俗的看一下这个例子 一家火锅店为了生意推出了一个特别活动 凡是在五一期间的老用户凡是卡里余额小于20的 赠送10元 但是这种活动没人只可享受一次 然后火锅店的后台程序员小王开始工作了
  • 悲观锁(Synchronized)和乐观锁(CAS)

    文章目录 悲观锁和乐观锁 Synchronized Synchronized使用 Synchronized底层原理 Java1 6对Synchronized的优化 synchronized的等待唤醒机制 CAS CAS使用 CAS底层原理
  • 悲观锁synchronized、乐观锁CAS

    1 悲观锁 乐观锁 悲观锁是一种思想 在多线程竞争下 加锁 释放锁会导致比较多的上下文切换和调度延时 引起性能问题 一个线程持有锁会导致其它所有需要此锁的线程挂起 如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置 引起性能
  • cas 编译安装依赖时提示: Failure to find net.shibboleth.tool:xmlsectool:jar:2.0.0

    错误信息 Could not resolve dependencies for project org apereo cas cas overlay war 1 0 Failure to find net shibboleth tool x
  • 面试必问的 CAS ,要多了解

    前言 CAS Compare and Swap 即比较并替换 实现并发算法时常用到的一种技术 Doug lea大神在java同步器中大量使用了CAS技术 鬼斧神工的实现了多线程执行的安全性 CAS的思想很简单 三个参数 一个当前内存值V 旧
  • 如何实施单点登录

    我想实现 SSO 单点登录 我发现了很多关于 CAS OpenID 和许多不同事物的链接和文章 我真的迷失了那么我应该使用 CAS 吗 我安装了 CAS Server 并将其部署到 Tomcat 中 你下一步怎么做 或者这是错误的 您能解释
  • CodeIgniter 的 CAS 身份验证库

    我正在尝试在 CodeIgniter 应用程序中实现 CAS 身份验证 但我找不到当前是否有为其设置的库 我通过只包含类并添加一些肮脏的修复来进行管理 但如果有人知道合适的库 我认为这将是一个更干净的解决方案 我一直在浏览这里以及谷歌上的一
  • 无锁堆栈实现想法 - 目前已损坏

    我想出了一个想法 尝试实现一个无锁堆栈 该堆栈不依赖引用计数来解决 ABA 问题 并且还可以正确处理内存回收 它在概念上与 RCU 类似 并且依赖于两个功能 将列表条目标记为已删除 以及跟踪遍历列表的读者 前者很简单 它只使用指针的LSB
  • 浏览器不遵循 AJAX 响应的重定向(PHP 生成的响应使用 CAS 身份验证)

    好吧 看来我最初的问题犯了一个错误 因此 这里有一些更正 答案仍然适用 因为当协议更改为 HTTPS SSL 时 第二个重定向就会停止 就我而言 重定向发生了多次 并且浏览器不遵循第二次重定向 遵循第一个重定向 但返回错误 我一直读到包含重
  • 使用 Spring Security 和 CAS 单点注销

    使用纯 Spring Java 配置 我在让 Spring 和 CAS 执行单点登录时遇到问题 我使用以下配置进行单点登录 我使用一个简单的 JSP 页面对 url 进行表单 POSThttps nginx shane com app lo
  • 通过cas进行ajax调用

    我需要编写一个谷歌小工具来读取谷歌群组的提要 问题是我正在进行 ajax 调用来检索提要 而我们的 google apps 域受 CAS 中央身份验证服务 保护 因此 我在拨打电话时收到 400 错误请求 我怀疑浏览器在进行 ajax 调用

随机推荐

  • GPT大语言模型Alpaca-lora本地化部署实践【大语言模型实践一】

    模型介绍 Alpaca模型是斯坦福大学研发的LLM Large Language Model 大语言 开源模型 是一个在52K指令上从LLaMA 7B Meta公司开源的7B 模型微调而来 具有70亿的模型参数 模型参数越大 模型的推理能力
  • 了解log4j日志平台

    log4j jar 写日志 log4j commonslog logback slf4j 通用的日志平台 推荐使用 还需要引入一个配置文件 log4j properties 需要放入classpath路径下 放在src下会自动加载到bin目
  • regsvr32提示模块加载失败 请确保二进制

    微软官方的一部分解释 https support microsoft com en us kb 249873 关于32位和64位的说明 http csi windows com blog all 73 windows 64 bit 378
  • 2021-05-20

    自我介绍 大家好 我是西安财经大学2019级大二的一名在校生 来自陕西省咸阳市 当时高考完在填报志愿的时候 我雨我的专业 一见钟情 计算机科学科学与技术专业 虽然有很多人告诉我说女孩子学IT这个行业不好 太辛苦太累等等 对于这些我都一笑了之
  • 多项式加法运算(链表实现)

    文章目录 创建结点类型 打印多项式 尾插 插入排序 多项式相加 代码总览 结果展示 创建结点类型 我们用链表存储一个多项式 那么该链表的每一个结点就代表多项式的某一项 所以我们的每一个结点必须包含三个信息 多项式的系数 多项式的指数以及指向
  • tf2报错解决 assertion failed: [predictions must be >= 0] [Condition x >= y did not hold element-wise:]

    环境 tf2 完整报错如下 tensorflow python framework errors impl InvalidArgumentError assertion failed predictions must be gt 0 Con
  • 理解主从设备模式(Master-Slave)

    主从设备模式 主从设备模式也叫做主仆模式英文简称为Master Slave 核心思想是基于分而治之的思想 将一个原始任务分解为若干个语义等同的子任务 并由专门的工作者线程来并行执行这些任务 原始任务的结果是通过整合各个子任务的处理结果形成的
  • 安卓APP_ Fragment(3)—— Fragment的生命周期

    摘自 安卓APP Fragment 3 Fragment的生命周期 作者 丶PURSUING 发布时间 2021 04 16 22 32 12 网址 https blog csdn net weixin 44742824 article d
  • LINUX进程启动时自动挂载调试

    对于某些多进程的应用 子进程是有主进程拉起来的 此时想对子进程的启动流程打断点就比较麻烦 如果在子进程启动时调试器自动挂载就完美了 网上找到了gdbhelpers的开源工具库 其对gdb的现有命令集做了扩展 有一个工具是实现预挂载的 原理也
  • (PPT+官方解读):中国移动5G终端产品2021年要这么干!

    以下内容来自官方解读 1 2020 年终端产品发展回顾 2020 年新冠疫情全球蔓延 生产和生活受到冲击也带来很多改变 应该说这是不平凡的一年 也是在这一年的不断努力之下 中国移动 5G 终端交出了一份还算不错的答卷 中国移动网内 5G 手
  • Html常用正则表达式

    Html常用正则表达式 匹配帐号是否合法 字母开头 允许5 16字节 允许字母数字下划线 a zA Z a zA Z0 9 4 15 验证用户密码 a zA Z w 5 17 正确格式为 以字母开头 长度在6 18之间 只能包含字符 数字和
  • Linux 其他用户(非root用户)设置root权限及免密(Centos7为例)

    在linux系统中我们经常要创建一些非root用户来完成一些特定的操作 有时我们需要执行一些root用户才能执行的命令 这时我们需要给该用户设置root的权限 下面将演示如何操作 1 首先创建一个test用户 root smiletian
  • Postman导出和导入接口

    1 点击Export导出接口 2 点击Export 3 导出成功 4 导入操作 import 5 选择导入文件 7 导入成功
  • vue element的el-select下拉框赋值之后无法选择

    watch监听form applicant applyUnit里值的变化 赋值给form project disposalType 但发现下拉框不能再次选择 watch form applicant applyUnit handler va
  • 2013年9月22日星期日(准备工作:分离ddraw的math和interface)

    在之前 要进行下封装 好吧 先加个类 ddraw math类吧 顺便把ddraw引擎中的几个矩阵弄到ddraw math类中来 让接口和数学相分离开 头文件有这些 pragma once a 2D vertex typedef struct
  • 表单提交时,get,post用哪种方式,如何设定?

    一般来说 使用 HTTP 的 POST 方法来提交表单 因为 POST 方法可以将表单数据作为请求正文发送到服务器 而 GET 方法将表单数据包含在请求 URL 中 在 HTML 中 可以通过在
  • 【裸机开发】UART 串口通信(二)—— 使用 UART 收发数据

    这节其实就是在对上一篇文章涉及到的一些操作进行整理和归纳 不一定完全按照上一篇的顺序来 目录 一 UART IO 初始化 二 UART 初始化 1 打开 关闭串口 2 软件复位 3 总结 UART 初始化 三 接收数据 四 发送数据 一 U
  • 【STM32】LCD液晶显示

    作者 一只大喵咪1201 专栏 STM32学习 格言 你只管努力 剩下的交给时间 LCD显示 LCD简介 TFTLCD驱动原理 ILI9341 液晶控制器简介 液晶屏的信号线及 8080 时序 使用 STM32 的 FSMC 模拟 8080
  • C语言知识小结(七)

    共用体 共用体是一种数据结构 结构体和共用体的区别 结构体 结构体的各个成员会占用不同的内存 互相之间没有影响 结构体占用的内存大于等于所有成员占用的内存的总和 成员之间可能存在缝隙 共用体占用的内存等于最长的成员占用的内存 共用体 共用体
  • AtomicStampedReference、AtomicMarkableReference源码分析,解决cas ABA问题

    cas的ABA问题就是 假设初始值为A 线程3和线程1都获取到了初始值A 然后线程1将A改为了B 线程2将B又改回了A 这时候线程3做修改时 是感知不到这个值从A改为了B又改回了A的过程 AtomicStampedReference 本质是