简述java中cas

本文介绍了Java中的CAS(Compare And Swap)原理,阐述了其通过比较并替换值来实现无锁操作的机制。接着,通过AtomicInteger示例展示了CAS的应用,并指出在并发环境下可能存在的ABA问题。为解决ABA问题,Java提供了AtomicStampedReference和AtomicMarkableReference类,它们通过额外的标记来判断对象是否发生变化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

cas原理

cas是compareAndSwap的缩写,可以看出就是比较比替换的意思。cas中有三个值,内存值V,旧的预期值E,更新值U,当且仅当V==E时,才进行更新,否则返回V。

cas应用

以java.util.concurrent包中的AtomicInteger为例。先演示代码:

public class AtomicIntegerTest {

	private static AtomicInteger atomicInteger=new AtomicInteger(5);//设置初始值

	public static void main(String[] args) {
		atomicInteger.compareAndSet(0,1);//0!=5,不变
		atomicInteger.compareAndSet(2,3);//2!=5,不变
		atomicInteger.compareAndSet(3,4);//3!=5,不变
		atomicInteger.compareAndSet(5,2);//5==5,更新为2
		atomicInteger.compareAndSet(0,4);//0!=2,不变

		System.out.println("result:"+atomicInteger.get());

	}
}

输出结果是:result:2

源码:

	/**使用 Unsafe.compareAndSwapInt()进行更新*/
		private static final Unsafe unsafe = Unsafe.getUnsafe();
		private static final long valueOffset;
		/**静态代码块对valueOffset进行初始化*/
		static {
			try {
				valueOffset = unsafe.objectFieldOffset
						(java.util.concurrent.atomic.AtomicInteger.class.getDeclaredField("value"));
			} catch (Exception ex) { throw new Error(ex); }
		}
		/**使用volatile修饰value,保证value值的一致性*/
		private volatile int value;

		/**
		 * 有参构构造方法
		 */
		public AtomicInteger(int initialValue) {
			value = initialValue;
		}

		/**
		 * 无参构造方法
		 */
		public AtomicInteger() {
		}

		/**
		 * 获取值
		 */
		public final int get() {
			return value;
		}

		/**
		 * 设置值
		 */
		public final void set(int newValue) {
			value = newValue;
		}

		/**
		 * 最终设置为给定值。
		 */
		public final void lazySet(int newValue) {
			unsafe.putOrderedInt(this, valueOffset, newValue);
		}

		/**
		 * 原子地设置为给定值并返回旧值。
		 *
		 */
		public final int getAndSet(int newValue) {
			return unsafe.getAndSetInt(this, valueOffset, newValue);
		}

		/**
		 *
		 * 若当前值等于期望的值,则更新给定的更新值
		 *
		 */
		public final boolean compareAndSet(int expect, int update) {
			return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
		}
		
		

		/**
		 *自增1
		 *
		 */
		public final int incrementAndGet() {
			return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
		}

		/**
		 * 自减1
		 *
		 */
		public final int decrementAndGet() {
			return unsafe.getAndAddInt(this, valueOffset, -1) - 1;
		}

		/**
		 * 增加给定的值
		 *
		 */
		public final int addAndGet(int delta) {
			return unsafe.getAndAddInt(this, valueOffset, delta) + delta;
		}

		/**
		 * 更新并返回原先的值
		 */
		public final int getAndUpdate(IntUnaryOperator updateFunction) {
			int prev, next;
			do {
				prev = get();
				next = updateFunction.applyAsInt(prev);
			} while (!compareAndSet(prev, next));
			return prev;
		}

		/**
		 * 返回更新之后的值
		 */
		public final int updateAndGet(IntUnaryOperator updateFunction) {
			int prev, next;
			do {
				prev = get();
				next = updateFunction.applyAsInt(prev);
			} while (!compareAndSet(prev, next));
			return next;
		}

原子包还有以下,用法基本一样。

cas中的ABA问题

  CAS可以有效的提升并发的效率,但同时也会引入ABA问题。

  如线程1从内存X中取出A,这时候另一个线程2也从内存X中取出A,并且线程2进行了一些操作将内存X中的值变成了B,然后线程2又将内存X中的数据变成A,这时候线程1进行CAS操作发现内存X中仍然是A,然后线程1操作成功。虽然线程1的CAS操作成功,但是整个过程就是有问题的。比如链表的头在变化了两次后恢复了原值,但是不代表链表就没有变化。

  所以JAVA中提供了AtomicStampedReference/AtomicMarkableReference来处理会发生ABA问题的场景,主要是在对象中额外再增加一个标记来标识对象是否有过变更。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值