CAS

CAS:Compare and Swap, 翻译成比较并交换。

java.util.concurrent包中借助CAS实现了区别于synchronized同步锁的一种乐观锁。

其原理是CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。

public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

ABA问题

    private static AtomicInteger atomicInt = new AtomicInteger(100);
public static void main(String[] args) throws InterruptedException {
Thread intT1 = new Thread(new Runnable() {
@Override
public void run() {
atomicInt.compareAndSet(100, 101);
log("thread intT1:" + atomicInt.get());
atomicInt.compareAndSet(101, 100);
log("thread intT1:" + atomicInt.get());
}
}); Thread intT2 = new Thread(new Runnable() {
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
boolean c3 = atomicInt.compareAndSet(100, 101);
log("thread intT2:" + atomicInt.get() + ",c3 is:" + c3); //true
}
}); intT1.start();
intT2.start();

上面程序的打印结果如下:

thread intT1:101
thread intT1:100
thread intT2:101,c3 is:true

线程intT2获取到的变量值A,尽管和当前的实际值相同,但内存地址V中的变量已经经历了A->B->A的改变。实际应用中有可能会导致漫画:什么是CAS机制?(进阶篇)中所提到的提款问题。

解决方案

JDK的atomic包里提供了一个类AtomicStampedReference来解决ABA问题。如果当前引用 == 预期引用,并且当前标志等于预期标志,则以原子方式将该引用和该标志的值设置为给定的更新值。源码如下:

/**
*expectedReference - 该引用的预期值
*newReference - 该引用的新值
*expectedStamp - 该标志的预期值
*newStamp - 该标志的新值
*/
public boolean compareAndSet(V expectedReference,
V newReference,
int expectedStamp,
int newStamp) {
Pair<V> current = pair;
return
expectedReference == current.reference &&
expectedStamp == current.stamp &&
((newReference == current.reference &&
newStamp == current.stamp) ||
casPair(current, Pair.of(newReference, newStamp)));
}

最佳实践

    private static AtomicStampedReference<Integer> atomicStampedRef =
new AtomicStampedReference<Integer>(100, 0); Thread refT1 = new Thread(new Runnable() {
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
atomicStampedRef.compareAndSet(100, 101,
atomicStampedRef.getStamp(), atomicStampedRef.getStamp() + 1);
log("thread refT1:" + atomicStampedRef.getReference());
atomicStampedRef.compareAndSet(101, 100,
atomicStampedRef.getStamp(), atomicStampedRef.getStamp() + 1);
log("thread refT1:" + atomicStampedRef.getReference());
}
}); Thread refT2 = new Thread(new Runnable() {
@Override
public void run() {
int stamp = atomicStampedRef.getStamp();
log("before sleep : stamp = " + stamp); // stamp = 0
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
log("after sleep : stamp = " + atomicStampedRef.getStamp());//stamp = 1
boolean c3 = atomicStampedRef.compareAndSet(100, 101, stamp, stamp + 1);
log("thread refT2:" + atomicStampedRef.getReference() + ",c3 is " + c3); //true
}
}); refT1.start();
refT2.start();
} private static void log(String logString) {
System.out.println(logString);
}

输出结果如下:

before sleep : stamp = 0
thread refT1:101
thread refT1:100
after sleep : stamp = 2
thread refT2:100,c3 is false

可以看到refT2的值和expect是相同的,但是由于版本号发生了变化,所以更新失败。

作者:时光之刃51y
链接:https://www.jianshu.com/p/8de8c6a839e8
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

CAS 的ABA 问题的更多相关文章

  1. 沉淀再出发:java中的CAS和ABA问题整理

    沉淀再出发:java中的CAS和ABA问题整理 一.前言 在多并发程序设计之中,我们不得不面对并发.互斥.竞争.死锁.资源抢占等等问题,归根到底就是读写的问题,有了读写才有了增删改查,才有了所有的一切 ...

  2. java并发编程(十三)----(JUC原子类)引用类型介绍(CAS和ABA的介绍)

    这一节我们将探讨引用类型原子类:AtomicReference, AtomicStampedRerence, AtomicMarkableReference.AtomicReference的使用非常简 ...

  3. CAS及其ABA问题

    CAS.volatile是JUC包实现同步的基础.Synchronized下的偏向锁.轻量级锁的获取.释放,lock机制下锁的获取.释放,获取失败后线程的入队等操作都是CAS操作锁标志位.state. ...

  4. Java高性能编程之CAS与ABA及解决方法

    Java高性能编程之CAS与ABA及解决方法 前言 如果喜欢暗色调的界面或者想换换界面,可以看看我在个人博客发布的 Java高性能编程之CAS与ABA及解决方法. CAS概念 CAS,全称Compar ...

  5. CAS的ABA问题详解

    CAS的ABA问题详解 ABA问题 在多线程场景下CAS会出现ABA问题,关于ABA问题这里简单科普下,例如有2个线程同时对同一个值(初始值为A)进行CAS操作,这三个线程如下 1.线程1,期望值为A ...

  6. CAS 和 ABA 问题

    CAS简介 CAS 全称是 compare and swap,是一种用于在多线程环境下实现同步功能的机制. CAS 它是一条CPU并发原语.操作包含三个操作数 -- 内存位置.预期数值和新值.CAS ...

  7. Java并发编程入门与高并发面试(三):线程安全性-原子性-CAS(CAS的ABA问题)

    摘要:本文介绍线程的安全性,原子性,java.lang.Number包下的类与CAS操作,synchronized锁,和原子性操作各方法间的对比. 线程安全性 线程安全? 线程安全性? 原子性 Ato ...

  8. Java CAS 和ABA问题

    独占锁:是一种悲观锁,synchronized就是一种独占锁,会导致其它所有需要锁的线程挂起,等待持有锁的线程释放锁. 乐观锁:每次不加锁,假设没有冲突去完成某项操作,如果因为冲突失败就重试,直到成功 ...

  9. 无锁编程(四) - CAS与ABA问题

    CAS 一般采用原子级的read-modify-write原语来实现Lock-Free算法,其中LL和SC是Lock-Free理论研究领域的理想原语,但实现这些原语需要CPU指令的支持,非常遗憾的是目 ...

  10. 谈论高并发(十二)分析java.util.concurrent.atomic.AtomicStampedReference看看如何解决源代码CAS的ABA问题

    于谈论高并发(十一)几个自旋锁的实现(五岁以下儿童)中使用了java.util.concurrent.atomic.AtomicStampedReference原子变量指向工作队列的队尾,为何使用At ...

随机推荐

  1. Leetcode春季打卡第四天:994. 腐烂的橘子

    Leetcode春季打卡第四天:994. 腐烂的橘子 Leetcode春季打卡第四天:994. 腐烂的橘子 思路 思路是采用广度优先搜索,一层一层遍历. 首先先扫描矩阵,将坏橘子放进队列,记录正常橘子 ...

  2. Java数据库分表与多线程查询结果汇总

    今天接到一个需求:要对一个物理分表的逻辑表进行查询统计.而数据库用的是公司自己研发的产品,考虑的到公司产品的特点以及业务的需求,该逻辑表是按年月进行分表的,而非分区.我们来看一下,在按时间段进行查询统 ...

  3. Python - 基础数据类型 list 列表

    什么是列表 列表是一个有序的序列 列表中所有的元素放在 [ ] 中间,并用逗号分开 一个 列表 可以包含不同类型的元素,但通常使用时各个元素类型相同 特征 占用空间小,浪费内存空间少 声明列表变量 列 ...

  4. Scanner的基本语法及用法

    一.Scanner对象 基本语法中并没有实现程序和人的交互,但是Java给我们提供了一个这样的工具类,我们可以获取用户的输入.java.util.Scanner是Java5的新特征,我们可以通过Sca ...

  5. Cent OS 7 本地yum源配置与安装

    一.本地yum源 1.添加一个新的yum源配置文件dvd.repo(文件名字自定义)  vi etc/yum.repos.d     添加新的内容: name=rhel_dvd            ...

  6. js 时间戳转为日期

    1 function time(){ //页面时间戳转换成时间 2 $(".time").each(function(){ 3 var time = $(this).text(); ...

  7. 百度nlp api接口测试

    date:2021/7/8 使用postman测试 网址:https://ai.baidu.com/ 在百度AI首页-开放能力-自然语言处理-语言处理基础技术 点击技术文档 在左侧文档目录选择API参 ...

  8. 一文读懂Spring动态配置多数据源---源码详细分析

    Spring动态多数据源源码分析及解读 一.为什么要研究Spring动态多数据源 ​ 期初,最开始的原因是:想将答题服务中发送主观题答题数据给批改中间件这块抽象出来, 但这块主要使用的是mq消息的方式 ...

  9. Spring学习笔记-Hello Spring

    实现原理 采用XML方式配置Bean的时候,Bean的定义和实现分离的,采用注解的方式可以将两者合为一体,Bean的定义信息直接以注解形式定义在实现类中,从而实现了零配置. 控制反转是一种通过描述(X ...

  10. Python实现多种SSH连接与文件传输

    Python实现SSH控制 使用Python进行基于口令认证的连接: 1 #加载paramiko包 2 import paramiko 3 #创建新的SSH对象 4 Client=paramiko.S ...