Java并发之CAS (Compare and Swap)(转载)
CAS(Compare and Swap)比较并替换,CAS是实现乐观锁的一个重要操作。
CAS 是一个硬件指令,保证是原子操作。
Java 中通过 UnSafe 来实现。
原子类: AtomicBoolean,AtomicInteger,AtomicLong 等使用 CAS 实现。
1. 概述
CAS 的基本步骤:执行函数 CAS(V,E,N),如果V值等于E值,则将V的值设为N。若V值和E值不同,则说明已经有其他线程做了更新,则当前线程什么都不做。
V表示要更新的变量
E表示预期值
N表示新值
Java 中 Unsafe 类提供 CAS 操作,CAS操作是本地方法(native),而且是不可改变(final)的:
下面三个方法的意思是:如果当前数值是 var4,则将 Java变量更新为 var5 或 var6 。var2 是Java变量在var1的中偏移量,用过偏移量获取Java变量的值。
public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5); public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5); public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);
2. 原子类的实现
原子类提供了一个性能高效、更加安全和用法,简单的变量操作。这里以AtomicInteger为例。
atomicInteger.getAndIncrement() , 当前值以原子的方式+1,但是返回+1之前的值,现在我们去探究一下该方法是如何实现的。
public final int getAndIncrement() { return unsafe.getAndAddInt(this, valueOffset, 1); }
==》unsafe 就是上面提到的 Unsafe类的一个实例对象。
private static final Unsafe unsafe = Unsafe.getUnsafe();
==》unsafe.getAndAddInt(this, valueOffset, 1):
var5 = this.getIntVolatile(var1, var2); 即 var5 为当前变量的值。
var5 和当前变量相等则 将 v5+v4 赋给当前变量,并返回 v5,即未+1之前的值。
public final int getAndAddInt(Object var1, long var2, int var4) { int var5; do { var5 = this.getIntVolatile(var1, var2); } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4)); return var5; }
==》this.getIntVolatile(var1, var2),获得对象var1,内存中偏移量为var2的成员变量值。
public native int getIntVolatile(Object var1, long var2);
3. 原子类的其他操作
运行截图:
3. 原子类实现一个自旋锁
原子类实现一个自旋锁代码如下所示:
public class SpinLock { private AtomicReference<Thread> owner =new AtomicReference<>(); public void lock(){ Thread current = Thread.currentThread(); while(!owner.compareAndSet(null, current)){ } } public void unlock (){ Thread current = Thread.currentThread(); owner.compareAndSet(current, null); } }
4. CAS 的缺点
4.1 CPU开销较大
在并发量比较高的情况下,多个线程反复尝试更新某一个变量,却又一直更新不成功,一直进行循环和尝试,会给CPU带来很大的压力。
4.2 ABA问题
你想要值A,如果在这段期间它的值曾经被改成了B,后来又被改回为A,那CAS操作就会误认为它从来没有被改变过。这个漏洞称为CAS操作的“ABA”问题。
Java并发包为了解决这个问题,提供了一个带有标记的原子引用类“AtomicStampedReference”,它可以通过控制变量值的版本来保证CAS的正确性。因此,在使用CAS前要考虑清楚“ABA”问题是否会影响程序并发的正确性,如果需要解决ABA问题,改用传统的互斥同步可能会比原子类更高效。
原文链接:https://blog.csdn.net/qq_38737992/article/details/90812550
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY