【转】-Java CAS操作的ABA问题
Java CAS操作的ABA问题
本文转载至ksfzhaohui的Java CAS操作的ABA问题
1. CAS介绍
比较并交换(compare and swap, CAS),是原子操作的一种,可用于在多线程编程中实现不被打断的数据交换操作,从而避免多线程同时改写某一数据时由于执行顺序不确定性以及中断的不可预知性产生的数据不一致问题。
CAS操作基于CPU提供的原子操作指令实现,各个编译器根据这个特点实现了各自的原子操作函数。来源维基百科:
C语言:由GNU提供了对应的__sync系列函数完成原子操作。
Windows:通过WindowsAPI实现了InterLocked Functions。
C++ 11:STL提供了atomic系列函数。
JAVA:sun.misc.Unsafe提供了compareAndSwap系列函数。
C#:通过Interlocked方法实现。
Go:通过import "sync/atomic"包实现。
java.util.concurrent包完全建立在CAS之上的,借助CAS实现了区别于synchronouse同步锁的一种乐观锁。
可以看一下AtomicInteger:
public final int getAndIncrement() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return current;
}
}
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
其中牵扯到3个值:current,next以及当前内存中的最新值,当且仅当current和内存中的最新值相同时,才会改变内存值为next。
2. CAS的ABA问题
ABA问题描述:
- 进程P1在共享变量中读到值为A
- P1被抢占了,进程P2执行
- P2把共享变量里的值从A改成了B,再改回到A,此时被P1抢占。
- P1回来看到共享变量里的值没有被改变,于是继续执行。
虽然P1以为变量值没有改变,继续执行了,但是这个会引发一些潜在的问题。ABA问题最容易发生在lock free的算法中的,CAS首当其冲,因为CAS判断的是指针的地址。如果这个地址被重用了呢,问题就很大了。(地址被重用是很经常发生的,一个内存分配后释放了,再分配,很有可能还是原来的地址)。
ABA问题解决方案
各种乐观锁的实现中通常都会用版本戳version来对记录或对象标记,避免并发操作带来的问题,在Java中,AtomicStampedReference也实现了这个作用,它通过包装类Pair[E,Integer]的元组来对对象标记版本戳stamp,从而避免ABA问题。
下面看一下AtomicInteger和AtomicStampedReference分别执行CAS操作:
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicStampedReference;
public class ABASingle {
public static void main(String[] args) {
AtomicInteger atomicInt = new AtomicInteger(100);
atomicInt.compareAndSet(100, 101);
atomicInt.compareAndSet(101, 100);
System.out.println("new value = " + atomicInt.get());
boolean result1 = atomicInt.compareAndSet(100, 101);
System.out.println(result1); // result:true
AtomicInteger v1 = new AtomicInteger(100);
AtomicInteger v2 = new AtomicInteger(101);
AtomicStampedReference<AtomicInteger> stampedRef = new AtomicStampedReference<AtomicInteger>(
v1, 0);
int stamp = stampedRef.getStamp();
stampedRef.compareAndSet(v1, v2, stampedRef.getStamp(),
stampedRef.getStamp() + 1);
stampedRef.compareAndSet(v2, v1, stampedRef.getStamp(),
stampedRef.getStamp() + 1);
System.out.println("new value = " + stampedRef.getReference());
boolean result2 = stampedRef.compareAndSet(v1, v2, stamp, stamp + 1);
System.out.println(result2); // result:false
}
}
AtomicInteger 执行cas操作成功,AtomicStampedReference执行cas操作失败。
这样是不是就是说AtomicInteger存在ABA问题,根本就不能用了;肯定是可以用的,AtomicInteger处理的一个数值,所有就算出现ABA问题问题,也不会有什么影响;但是如果这里是一个地址 (地址被重用是很经常发生的,一个内存分配后释放了,再分配,很有可能还是原来的地址) ,比较地址发现没有问题,但其实这个对象早就变了,这时候就可以使用AtomicStampedReference来解决ABA问题。
【转】-Java CAS操作的ABA问题的更多相关文章
- 并发中的Native方法,CAS操作与ABA问题
Native方法,Unsafe与CAS操作 >>JNI和Native方法 Java中,通过JNI(Java Native Interface,java本地接口)来实现本地化,访问操作系统底 ...
- 【Java并发编程实战】-----“J.U.C”:CAS操作
CAS,即Compare and Swap,中文翻译为"比较并交换". 对于JUC包中,CAS理论是实现整个java并发包的基石.从整体来看,concurrent包的实现示意图如下 ...
- Java CAS 和ABA问题
独占锁:是一种悲观锁,synchronized就是一种独占锁,会导致其它所有需要锁的线程挂起,等待持有锁的线程释放锁. 乐观锁:每次不加锁,假设没有冲突去完成某项操作,如果因为冲突失败就重试,直到成功 ...
- java并发:CAS算法和ABA问题
CAS算法是硬件对于并发的支持,针对多处理器操作而设计的处理器中的一种特殊指令. CAS用于管理对共享数据的并发访问. java的并发包中,AQS.原子操作类等都是基于CAS实现的. CAS 是一种 ...
- Java CAS ABA问题发生的场景分析
提到了CAS操作存在问题,就是在CAS之前A变成B又变回A,CAS还是能够设置成功的,什么场景下会出现这个问题呢?查了一些资料,发现在下面的两种情况下会出现ABA问题. 1.A最开始的内存地址是X,然 ...
- 深入浅出 Java Concurrency (5): 原子操作 part 4 CAS操作
在JDK 5之前Java语言是靠synchronized关键字保证同步的,这会导致有锁(后面的章节还会谈到锁). 锁机制存在以下问题: (1)在多线程竞争下,加锁.释放锁会导致比较多的上下文切换和调度 ...
- Java乐观锁实现之CAS操作
介绍CAS操作前,我们先简单看一下乐观锁 与 悲观锁这两个常见的锁概念. 悲观锁: 从Java多线程角度,存在着“可见性.原子性.有序性”三个问题,悲观锁就是假设在实际情况中存在着多线程对同一共享的竞 ...
- 多线程之:java的CAS操作的相关信息
一:锁机制存在的性能问题? 在JDK 5之前Java语言是靠synchronized关键字保证同步的,这会导致有锁(后面的章节还会谈到锁). 锁机制存在以下问题:(1)在多线程竞争下,加锁.释放锁会导 ...
- java高并发系列 - 第21天:java中的CAS操作,java并发的基石
这是java高并发系列第21篇文章. 本文主要内容 从网站计数器实现中一步步引出CAS操作 介绍java中的CAS及CAS可能存在的问题 悲观锁和乐观锁的一些介绍及数据库乐观锁的一个常见示例 使用ja ...
- Java并发指南3:并发三大问题与volatile关键字,CAS操作
本文转载自互联网,侵删 序言 先来看如下这个简单的Java类,该类中并没有使用任何的同步. 01 final class SetCheck { 02 private int a = 0; 03 ...
随机推荐
- SQL 强化练习 (十二)
还是 sql 冲鸭... , 停不下来了都, 趁着激情还在, 赶紧再整一把, 也渐渐发现, sql 果然是非常强大的, 然后搞了半天, 发现在写sql 的时候, 从它执行顺序来思考, 这样反而会轻松很 ...
- hashlib标准库简单使用
哈希算法/摘要算法是通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示). 该库对于不同的哈希算法/摘要算法都提供了通用的接口,比如FIPS算法中的SHA1,SHA2 ...
- 航空货运系统总结性Blog
前言 本次题目集以航空运送货物为背景,设计航空货物管理系统,主要考察对类设计的把握是否合理还有对继承和多态的使用,能否设计出符合标准的类,是否充分理解对面向对象六大设计原则(SRP,OCP,LSP,D ...
- slf4j、logback、log4j、log4j2的区别
区别 slf4j是一个日志接口,自己没有具体实现日志系统,只提供了一组标准的调用api,这样将调用和具体的日志实现分离,使用slf4j后有利于根据自己实际的需求更换具体的日志系统,比如,之前使用的具体 ...
- windows系统部署minio
下载 在官网下载exe https://dl.min.io/server/minio/release/windows-amd64/ 创建文件夹 把minio.exe放到一个文件夹里,然后同目录里再新建 ...
- 洛谷 P6626 [省选联考 2020 B 卷] 消息传递
洛谷 P6626 [省选联考 2020 B 卷] 消息传递 Problem 原题传送门 给一棵有\(n\)个节点的树.有\(m\)个询问,每次给出一对\(x,k\)表示查询到点\(x\)的距离为\(k ...
- 初识protobuf
protobuf的优点 性能方面 序列化后,数据大小可缩小3倍 序列化速度快 传输速度快 使用方面 使用简单:proto编译器自动进行序列化和反序列化 维护成本低:多平台只需要维护一套对象协议文件,即 ...
- ArrayList与LinkedList性能比较
ArrayList 1 package com.lv.study.pm.first; 2 3 import java.util.ArrayList; 4 import java.util.Linked ...
- 知名开源项目Alist被收购!惹程序员众怒,开团炮轰甲方
知名开源网盘项目 Alist 被黑产收购?涉及泄露用户隐私?众多开发者成为黑奴?程序员集体炮轰项目评论区? 听起来还挺炸裂的,作为一名程序员,带大家扒一扒这个事件的来龙去脉. 什么是 Alist? A ...
- [书籍精读]《CSS世界》精读笔记分享
写在前面 书籍介绍:本书从前端开发人员的需求出发,以"流"为线索,从结构.内容到美化装饰等方面,全面且深入地讲解前端开发人员必须了解和掌握的大量的CSS知识点.同时,作者结合多年的 ...