CAS 的ABA 问题
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 问题的更多相关文章
- 沉淀再出发:java中的CAS和ABA问题整理
沉淀再出发:java中的CAS和ABA问题整理 一.前言 在多并发程序设计之中,我们不得不面对并发.互斥.竞争.死锁.资源抢占等等问题,归根到底就是读写的问题,有了读写才有了增删改查,才有了所有的一切 ...
- java并发编程(十三)----(JUC原子类)引用类型介绍(CAS和ABA的介绍)
这一节我们将探讨引用类型原子类:AtomicReference, AtomicStampedRerence, AtomicMarkableReference.AtomicReference的使用非常简 ...
- CAS及其ABA问题
CAS.volatile是JUC包实现同步的基础.Synchronized下的偏向锁.轻量级锁的获取.释放,lock机制下锁的获取.释放,获取失败后线程的入队等操作都是CAS操作锁标志位.state. ...
- Java高性能编程之CAS与ABA及解决方法
Java高性能编程之CAS与ABA及解决方法 前言 如果喜欢暗色调的界面或者想换换界面,可以看看我在个人博客发布的 Java高性能编程之CAS与ABA及解决方法. CAS概念 CAS,全称Compar ...
- CAS的ABA问题详解
CAS的ABA问题详解 ABA问题 在多线程场景下CAS会出现ABA问题,关于ABA问题这里简单科普下,例如有2个线程同时对同一个值(初始值为A)进行CAS操作,这三个线程如下 1.线程1,期望值为A ...
- CAS 和 ABA 问题
CAS简介 CAS 全称是 compare and swap,是一种用于在多线程环境下实现同步功能的机制. CAS 它是一条CPU并发原语.操作包含三个操作数 -- 内存位置.预期数值和新值.CAS ...
- Java并发编程入门与高并发面试(三):线程安全性-原子性-CAS(CAS的ABA问题)
摘要:本文介绍线程的安全性,原子性,java.lang.Number包下的类与CAS操作,synchronized锁,和原子性操作各方法间的对比. 线程安全性 线程安全? 线程安全性? 原子性 Ato ...
- Java CAS 和ABA问题
独占锁:是一种悲观锁,synchronized就是一种独占锁,会导致其它所有需要锁的线程挂起,等待持有锁的线程释放锁. 乐观锁:每次不加锁,假设没有冲突去完成某项操作,如果因为冲突失败就重试,直到成功 ...
- 无锁编程(四) - CAS与ABA问题
CAS 一般采用原子级的read-modify-write原语来实现Lock-Free算法,其中LL和SC是Lock-Free理论研究领域的理想原语,但实现这些原语需要CPU指令的支持,非常遗憾的是目 ...
- 谈论高并发(十二)分析java.util.concurrent.atomic.AtomicStampedReference看看如何解决源代码CAS的ABA问题
于谈论高并发(十一)几个自旋锁的实现(五岁以下儿童)中使用了java.util.concurrent.atomic.AtomicStampedReference原子变量指向工作队列的队尾,为何使用At ...
随机推荐
- [刘阳Java]_Java基础面试中的常识问题
1. anonymous inner class(匿名内部类)是否可以extends(继承)其它类,是否可以implements(实现)interface(接口)? 不行,对于匿名内部类,看到的一句话 ...
- Album++:分布式事务专辑-基础概念
(一)基础概念:↓ ↓ ↓ 1.1)什么是事务 什么是事务?举个生活中的例子:你去小卖铺买东西,"一手交钱,一手交货"就是一个事务的例子,交钱和交货必 须全部成功, 事务才算成功, ...
- Java 使用新方法打印Word文档
前言 我曾写过一篇文章,它主要介绍了如何通过物理打印机和虚拟打印机来打印Word文档.今天这篇教程将介绍一种新的方法来实现对Word文档的打印. 此次使用到的类库仍然是Spire.Doc for Ja ...
- 在java中为啥要重写toString 方法?
在java中为啥要重写toString 方法?下面以一个简单的例子来说明. 先定义一个test5类.并写它的get,set方法. package test5; public class Test5 { ...
- odoo里的javascript学习---自定义插件
插件效果图 定义js odoo.define('auto_widget',function(require){ "use strict"//通过扩展AbstractField来扩展 ...
- 用Pygal画一个英雄能力的图
效果图: 这是在google浏览器下打开的html. play.py #!/usr/bin/env python # _*_ coding: UTF-8 _*_ """= ...
- bs4爬取笔趣阁小说
参考链接:https://www.cnblogs.com/wt714/p/11963497.html 模块:requests,bs4,queue,sys,time 步骤:给出URL--> 访问U ...
- 实时 + 高清 + 超压缩,阿里云视频云发布业内首款 VVC 编码器 Ali266
基于新一代国际视频编解码标准 H.266/VVC,阿里云视频云近日发布了实时高清编码器 Ali266,有力推动 H.266/VVC 标准应用的落地,真正开启 H.266/VVC 的商用之路,并强力赋能 ...
- 深入刨析tomcat 之---第9篇 how tomcat works 第9章,Session的实现 关于request.setContext(context)
writedby 张艳涛,在学第9章session的时候,做了个实验在给的demo代码中添加了 package com.zyt.tomcat.ex09.core; public class Simpl ...
- Mariadb常用管理操作
一 Mariadb常用管理操作 纯干货,没有一点废话,全是使用频率最高和常用的操作,运维必不可少的基础资料. 1.1 创建数据库 >create database <db_name> ...