2.原子--AtomicStampedReference解决ABA问题

AtomicStampedReference解决ABA问题

在运用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失败:

public class Test {

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

}

2.原子--AtomicStampedReference解决ABA问题

时间: 2024-10-25 06:39:05

2.原子--AtomicStampedReference解决ABA问题的相关文章

用AtomicStampedReference解决ABA问题

在运用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执行上面这条指令之

Java CAS 和ABA问题

http://www.cnblogs.com/549294286/p/3766717.html 独占锁:是一种悲观锁,synchronized就是一种独占锁,会导致其它所有需要锁的线程挂起,等待持有锁的线程释放锁. 乐观锁:每次不加锁,假设没有冲突去完成某项操作,如果因为冲突失败就重试,直到成功为止. 一.CAS 操作 乐观锁用到的机制就是CAS,Compare and Swap. CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B.当且仅当预期值A和内存值V相同时,将内存值V修改为B,

Java JUC之Atomic系列12大类实例讲解和原理分解

Java JUC之Atomic系列12大类实例讲解和原理分解 2013-02-21      0个评论       作者:xieyuooo 收藏    我要投稿 在java6以后我们不但接触到了Lock相关的锁,也接触到了很多更加乐观的原子修改操作,也就是在修改时我们只需要保证它的那个瞬间是安全的即可,经过相应的包装后可以再处理对象的并发修改,以及并发中的ABA问题,本文讲述Atomic系列的类的实现以及使用方法,其中包含: 基本类:AtomicInteger.AtomicLong.Atomic

J.U.C CAS

在JDK1.5之前,也就是J.U.C加入JDK之前,Java是依靠synchronized关键字(JVM底层提供)来维护协调对共享字段的访问,保证对这些变量的独占访问权,并且以后其他线程忽的该锁时,将可以看到对这些变量进行的更改(可见性,互斥性). 锁机制的问题: 锁问题不可回避的,就是上下文切换,加重系统线程调度,引起性能问题: 不一致的获得多个锁的顺序,还可能引发死锁: 如果一个线程试图获得其他线程已经具有的锁时,那么该线程将被阻塞,直到该锁可用,期间它无法进行其他任何操作,试想对一组操作序

java之高并发与多线程

进程和线程的区别和联系 从资源占用,切换效率,通信方式等方面解答 线程具有许多传统进程所具有的特征,故又称为轻型进程(Light—Weight Process)或进程元:而把传统的进程称为重型进程(Heavy—Weight Process),它相当于只有一个线程的任务.在引入了线程的操作系统中,通常一个进程都有若干个线程,至少需要一个线程.下面,我们从调度.并发性. 系统开销.拥有资源等方面,来比较线程与进程. 1.调度 在传统的操作系统中,拥有资源的基本单位和独立调度.分派的基本单位都是进程.

【死磕Java并发】----深入分析CAS

CAS,Compare And Swap,即比较并交换.Doug lea大神在同步组件中大量使用CAS技术鬼斧神工地实现了Java多线程的并发操作.整个AQS同步组件.Atomic原子类操作等等都是以CAS实现的,甚至ConcurrentHashMap在1.8的版本中也调整为了CAS+Synchronized.可以说CAS是整个JUC的基石. CAS分析 在CAS中有三个参数:内存值V.旧的预期值A.要更新的值B,当且仅当内存值V的值等于旧的预期值A时才会将内存值V的值修改为B,否则什么都不干.

Java CAS简析

什么是CAS CAS:Compare and Swap,它是一种原子操作,什么是原子操作,可以在多线程编程中实现数据交换而不被打断.是用来更新变量的,当多个线程使用CAS来更新变量时,只有一个线程可以更新变量的值,其他线程都会失败,失败的线程不回被挂起,而是重试直到成功为止. CAS实现方式,有三个变量,内存值V,处理器缓存(预期值)A,更新值B.比较内存值与预期值,相等则说明没有其他线程操作共享数据,则更新内存值为B:不等说明共享数据V已经被其他线程改动了,放弃更新操作,重新load共享数据,

后端开发优秀博客文章收集

1.集合类 ArrayList源码分析(基于JDK8) ConcurrentHashMap总结 2.三大框架 CGLIB介绍与原理 我们为什么要使用AOP? MyBatis框架及原理分析 3.Redis/Mysql Redis到底是多线程还是单线程? 数据库MySQL由浅入深理解索引的实现 4.多线程 ThreadLocal从源码分析总结到内存泄漏 Java中Synchronized的用法 AtomicStampedReference解决ABA问题 三个线程循环打印ABC10次的几种解决方法 j

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

在聊聊高并发(十一)实现几种自旋锁(五)中使用了java.util.concurrent.atomic.AtomicStampedReference原子变量指向工作队列的队尾,为何使用AtomicStampedReference原子变量而不是使用AtomicReference是因为这个实现中等待队列的同一个节点具备不同的状态,而同一个节点会多次进出工作队列,这就有可能出现出现ABA问题. 熟悉并发编程的同学应该知道CAS操作存在ABA问题.我们先看下CAS操作. CAS(Compare and