文档章节

AtomicStampedReference解决ABA问题

果子核
 果子核
发布于 2017/06/04 09:49
字数 605
阅读 3
收藏 0

在运用CAS做Lock-Free操作中有一个经典的ABA问题:

线程1准备用CAS将变量的值由A替换为B,在此之前,线程2将变量的值由A替换为C,又由C替换为A,然后线程1执行CAS时发现变量的值仍然为A,所以CAS成功。但实际上这时的现场已经和最初不同了,尽管CAS成功,但可能存在潜藏的问题,例如下面的例子:

现有一个用单向链表实现的堆栈,栈顶为A,这时线程T1已经知道A.next为B,然后希望用CAS将栈顶替换为B:

head.compareAndSet(A,B);

在T1执行上面这条指令之前,线程T2介入,将A、B出栈,再pushD、C、A,此时堆栈结构如下图,而对象B此时处于游离状态:

此时轮到线程T1执行CAS操作,检测发现栈顶仍为A,所以CAS成功,栈顶变为B,但实际上B.next为null,所以此时的情况变为:

其中堆栈中只有B一个元素,C和D组成的链表不再存在于堆栈中,平白无故就把C、D丢掉了。

以上就是由于ABA问题带来的隐患,各种乐观锁的实现中通常都会用版本戳version来对记录或对象标记,避免并发操作带来的问题,在Java中,AtomicStampedReference<E>也实现了这个作用,它通过包装[E,Integer]的元组来对对象标记版本戳stamp,从而避免ABA问题,例如下面的代码分别用AtomicInteger和AtomicStampedReference来对初始值为100的原子整型变量进行更新,AtomicInteger会成功执行CAS操作,而加上版本戳的AtomicStampedReference对于ABA问题会执行CAS失败:

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicStampedReference;

public class ABA {
        private static AtomicInteger atomicInt = new AtomicInteger(100);
        private static AtomicStampedReference atomicStampedRef = new AtomicStampedReference(100, 0);

        public static void main(String[] args) throws InterruptedException {
                Thread intT1 = new Thread(new Runnable() {
                        @Override
                        public void run() {
                                atomicInt.compareAndSet(100, 101);
                                atomicInt.compareAndSet(101, 100);
                        }
                });

                Thread intT2 = new Thread(new Runnable() {
                        @Override
                        public void run() {
                                try {
                                        TimeUnit.SECONDS.sleep(1);
                                } catch (InterruptedException e) {
                                }
                                boolean c3 = atomicInt.compareAndSet(100, 101);
                                System.out.println(c3); // true
                        }
                });

                intT1.start();
                intT2.start();
                intT1.join();
                intT2.join();

                Thread refT1 = new Thread(new Runnable() {
                        @Override
                        public void run() {
                                try {
                                        TimeUnit.SECONDS.sleep(1);
                                } catch (InterruptedException e) {
                                }
                                atomicStampedRef.compareAndSet(100, 101, atomicStampedRef.getStamp(), atomicStampedRef.getStamp() + 1);
                                atomicStampedRef.compareAndSet(101, 100, atomicStampedRef.getStamp(), atomicStampedRef.getStamp() + 1);
                        }
                });

                Thread refT2 = new Thread(new Runnable() {
                        @Override
                        public void run() {
                                int stamp = atomicStampedRef.getStamp();
                                try {
                                        TimeUnit.SECONDS.sleep(2);
                                } catch (InterruptedException e) {
                                }
                                boolean c3 = atomicStampedRef.compareAndSet(100, 101, stamp, stamp + 1);
                                System.out.println(c3); // false
                        }
                });

                refT1.start();
                refT2.start();
        }
}

ABA问题。 […]

本文转载自:http://blog.hesey.net/2011/09/resolve-aba-by-atomicstampedreference.html

共有 人打赏支持
果子核
粉丝 2
博文 39
码字总数 10055
作品 0
海淀
程序员
Java CAS操作的ABA问题

CAS介绍 比较并交换(compare and swap, CAS),是原子操作的一种,可用于在多线程编程中实现不被打断的数据交换操作,从而避免多线程同时改写某一数据时由于执行顺序不确定性以及中断的不可预...

ksfzhaohui
2016/11/22
1K
4
【死磕Java并发】----深入分析CAS

CAS,Compare And Swap,即比较并交换。Doug lea大神在同步组件中大量使用CAS技术鬼斧神工地实现了Java多线程的并发操作。整个AQS同步组件、Atomic原子类操作等等都是以CAS实现的,甚至Concu...

chenssy
2017/04/07
0
0
Java并发--原子变量类的使用

注:本篇博客主要内容来源于网络,侵删~ 引言 我们假设你已经熟练掌握了CAS,原子变量类等的相关概念。这篇博客中,我们主要讨论原子变量类的使用。 原子变量类 原子变量类共12个,分4组: ...

珩翊
10/03
0
0
JDK原子类源码分析

JDK中的java.util.concurrent.atomic包提供了一系列支持无锁线程安全修改操作的基础变量。这些原子类是对volatile机制的扩展,并且提供了一系列CAS原子操作方法如: 这些CAS方法使得我们能够...

Justlearn
2017/04/17
0
0
AtomicStampedReference的问题

CAS的 ” ABA 问题”可以用AtomicStampedReference解决 为什么单独执行下面代码结果为"true",在多线程下就是false了呢??源码看的实在是晕,虽然就几行代码,那位大侠能解释下?? 第一部,...

crazygooo
2013/11/01
416
0

没有更多内容

加载失败,请刷新页面

加载更多

javascript source map 的使用

之前发现VS.NET会为压缩的js文添加一个与文件名同名的.map文件,一直没有搞懂他是用来做什么的,直接删除掉运行时浏览器又会报错,后来google了一直才真正搞懂了这个小小的map文件背后的巨大...

粒子数反转
昨天
0
0
谈谈如何学Linux和它在如今社会的影响

昨天,还在农耕脑力社会,今天已经人工智能技术、大数据、信息技术的科技社会了,高速开展并迅速浸透到当今科技社会的各个方面,Linux日益成为人们信息时代的到来,更加考验我们对信息的处理程...

linux-tao
昨天
0
0
学习设计模式——中介者模式

1. 认识中介者模式 1. 定义:用一个中介对象来封装一系列的对象交互行为,中介者使得各对象不需要显式的互相引用,从而使其松散耦合,独立的改变他们之间的交互。 2. 结构: Mediator:中介者...

江左煤郎
昨天
0
0
深入理解Plasma(1):Plasma 框架

这一系列文章将围绕以太坊的二层扩容框架,介绍其基本运行原理,具体操作细节,安全性讨论以及未来研究方向等。本篇文章作为开篇,主要目的是理解 Plasma 框架。 Plasma 作为以太坊的二层扩容...

HiBlock
昨天
0
0
Java 8 日期 示例

Java 8 推出了全新的日期时间API。Java处理日期、日历和时间的方式一直为社区所诟病,将 java.util.Date设定为可变类型,以及SimpleDateFormat的非线程安全使其应用非常受限。Java也意识到需...

阿刚ABC
昨天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部