`
lingzantia
  • 浏览: 150015 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

用AtomicStampedReference解决ABA问题

    博客分类:
  • Java
 
阅读更多

在运用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();
        }
}

 

分享到:
评论

相关推荐

    atomicReference 使用和AtomicStampedReference 解决ABA的问题.docx

    为了解决ABA问题,我们可以使用`AtomicStampedReference`。`AtomicStampedReference`除了保存对象引用外,还保存了一个称为"stamp"或"version"的整数值,用于记录状态的变化。在上述`AtomicStampedReferenceTest`的...

    CAS底层原理与ABA问题.docx

    为了解决这个问题,可以使用版本号或者“戳”来记录变量的状态,如Java中的`AtomicStampedReference`类,它包含了一个值和一个版本号,可以在比较时同时检查值和版本号是否一致。 `Unsafe`类中的`getAndAddInt`方法...

    CAS原理 java 并发

    **二、AtomicStampedReference解决ABA问题** 在并发编程中,一个常见的问题是ABA问题。假设线程A首先读取了一个值为A的对象引用,然后线程B将其更改为B,接着又改回为A。线程A再次检查时,会认为值没有改变,但实际...

    常见的Java笔试题-JVM-JUC-Core:JUCJVM核心知识点

    AtomicStampedReference和ABA问题的解决 集合类不安全问题 List CopyOnWriteArrayList Set HashSet和HashMap Map Java锁 公平锁/非公平锁 可重入锁/递归锁 锁的配对 自旋锁 读写锁/独占/共享锁 Synchronized和Lock的...

    Java高并发编程详解.md

    ```AtomicStampedReference```来解决ABA问题,类中的```compareAndSet```方法作用首先检查当前引用是否等于预期引用,并且当前标志是否等于预期标志,如果相等,以原子方式将该引用和标记的值设置为给定的更新值。

    Java并发编程原理精讲 视频教程 下载 因为太大 百度网盘链接4.zip

    ├─01 第一章 线程基础 │ ├─01 线程概述 │ │ 01 认识线程.mp4 │ │ 02 线程和进程的关系.mp4 │ │ 03 并发和并行的区别.mp4 │ │ 04 并发编程的应用场景...│ 08 使用AtomicStampedReference演示ABA问题.

    Java并发编程原理精讲 视频教程 下载 因为太大 百度网盘链接3.zip

    ├─01 第一章 线程基础 │ ├─01 线程概述 │ │ 01 认识线程.mp4 │ │ 02 线程和进程的关系.mp4 │ │ 03 并发和并行的区别.mp4 │ │ 04 并发编程的应用场景...│ 08 使用AtomicStampedReference演示ABA问题.

    Java并发编程原理精讲 视频教程 下载 因为太大 百度网盘链接1.zip

    ├─01 第一章 线程基础 │ ├─01 线程概述 │ │ 01 认识线程.mp4 │ │ 02 线程和进程的关系.mp4 │ │ 03 并发和并行的区别.mp4 │ │ 04 并发编程的应用场景...│ 08 使用AtomicStampedReference演示ABA问题.

    Java并发编程原理精讲 视频教程 下载 因为太大 百度网盘链接2.zip

    ├─01 第一章 线程基础 │ ├─01 线程概述 │ │ 01 认识线程.mp4 │ │ 02 线程和进程的关系.mp4 │ │ 03 并发和并行的区别.mp4 │ │ 04 并发编程的应用场景...│ 08 使用AtomicStampedReference演示ABA问题.

    笔记-3、原子操作CAS1

    为了解决ABA问题,Java提供了一些特殊的原子类,如`AtomicMarkableReference`和`AtomicStampedReference`。`AtomicMarkableReference`在引用对象的基础上添加了一个可原子性设置的标记位,可以用来检测变量是否被...

    CAS学习手册-JAVA程序员必备

    Java通过`AtomicStampedReference`或`AtomicMarkableReference`类来解决ABA问题,它们增加了版本戳或标记,确保即使值回到原值,也能检测到中间状态的变化。 6. **Java中的CAS实现** CAS操作在Java中通过JNI...

    Java 多线程与并发(8-26)-JUC原子类- CAS, Unsafe和原子类详解.pdf

    为了解决ABA问题,Java提供了AtomicStampedReference和AtomicMarkableReference类。这两个类在操作值的时候,会一同更新一个"版本号"或"标记",从而避免ABA问题。此外,自旋CAS长时间不成功可能会导致CPU资源的浪费...

    面试必备之乐观锁与悲观锁.pdf

    JDK1.5引入了AtomicStampedReference类来解决ABA问题,通过引入版本号或时间戳来确保操作的原子性。另外,乐观锁如果重试次数过多,也会导致CPU开销增大,因此在使用乐观锁时需要权衡性能与资源消耗。 在实际应用中...

    【并发编程】CAS到底是什么.pdf

    **原子引用类**:如`AtomicStampedReference`,它不仅存储值还存储版本号,可以解决ABA问题。 #### 六、CPU空转及其解决方案 - **CPU空转**:当线程在等待某些条件满足时,可能会反复检查条件是否满足,导致CPU...

    Thread基础知识点笔记总结

    AtomicStampedReference 是一个原子引用类,用于解决 ABA 问题,通过加了版本进行控制。 4. Collections Java 中的集合类在多线程环境下是不安全的,例如 ArrayList。在高并发的情况下使用 ArrayList 的时候,会...

    CAS简介以及CAS的缺点和处理方法

    以下是一个使用`AtomicStampedReference`解决ABA问题的示例: ```java AtomicStampedReference atomicStampedReference = new AtomicStampedReference(100, 1); // ... int stamp = atomicStampedReference....

    不可不说的Java"锁"事1

    JDK 1.4之后,Java原子类提供了`AtomicStampedReference`和`AtomicMarkableReference`来解决这个问题,它们可以附加额外的信息来标记状态变化。 总的来说,Java中的锁机制和CAS操作提供了多种处理并发问题的方式。...

Global site tag (gtag.js) - Google Analytics