城乡建设与环保部网站,高端建站价格,网络职业有哪些,什么是网站前台上一期文章内容#xff1a;Java并发中的乐观锁与悲观锁#xff0c; 本期文章我们来讲一下Java并发中的CAS机制 一、从银行账户案例理解CAS CAS 是一种乐观锁机制#xff0c;用于在不使用锁的情况下实现多线程对共享资源的并发访问。 它包含三个操作数#xff1a;内存位置Java并发中的乐观锁与悲观锁 本期文章我们来讲一下Java并发中的CAS机制 一、从银行账户案例理解CAS CAS 是一种乐观锁机制用于在不使用锁的情况下实现多线程对共享资源的并发访问。 它包含三个操作数内存位置V、预期原值A和新值B。 当且仅当内存位置 V 的值等于预期原值 A 时才将内存位置 V 的值更新为新值 B 否则不做任何操作。整个 CAS 操作是原子性的由 CPU 硬件指令直接支持。 想象这样一个场景你和朋友同时查看一个银行账户余额为100元你们都尝试转账。传统做法是银行用锁机制只允许一人操作。而CASCompare-And-Swap比较交换采用更聪明的策略 你查询当前余额100元旧值 系统记录此刻的版本号为V1 当你提交转账时系统会检查 当前余额是否仍是100元 版本号是否还是V1 只有当两者都满足时转账才会成功并更新版本号为V2 这种无锁机制就像超市自助结账——不需要收银员锁顾客线程自己完成操作系统通过版本检查保证安全。 二、Java底层实现揭秘
2.1 神秘的Unsafe类
Java通过sun.misc.Unsafe类实现CAS这个类就像Java世界的瑞士军刀为什么会这么说呢
因为 sun.misc.Unsafe 类功能强大并且多样提供了直接操作内存、基于CAS的操作方法、线程调度相关方法等的能力但是我们在使用时需要持谨慎态度因为会涉及安全、可移植、代码维护等问题
public final class Unsafe {// 对象类型CASpublic final native boolean compareAndSwapObject(Object obj, long offset, Object expect, Object update);// int类型CASpublic final native boolean compareAndSwapInt(Object obj, long offset, int expect, int update);// long类型CASpublic final native boolean compareAndSwapLong(Object obj, long offset, long expect, long update);
}
通过JNI调用本地代码最终映射到CPU指令如x86的CMPXCHG整个过程就像 获取当前值 计算新值 调用CPU指令进行原子比较交换 2.2 AtomicInteger实现解析
以AtomicInteger为例看Java如何包装CAS
public class AtomicInteger {private volatile int value; // 保证可见性private static final Unsafe unsafe Unsafe.getUnsafe();private static final long valueOffset; // 内存偏移量static {try {valueOffset unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField(value));} catch (Exception ex) { throw new Error(ex); }}public final boolean compareAndSet(int expect, int update) {return unsafe.compareAndSwapInt(this, valueOffset, expect, update);}
}
关键点说明 volatile保证值变更的可见性 内存偏移量定位字段位置 CAS失败时自动重试自旋 三、CAS的三大挑战与应对
3.1 ABA问题账户余额的时空穿越
假设账户余额变化100 → 200 → 100 线程A读取100版本V1 线程B完成两次修改V1→V2→V3 线程A的CAS检查值仍是100但版本已变化 解决方案 使用带版本号的AtomicStampedReference
AtomicStampedReferenceInteger account new AtomicStampedReference(100, 0);// 存款操作
int[] stampHolder new int[1];
int current account.get(stampHolder);
if(account.compareAndSet(current, current50, stampHolder[0], stampHolder[0]1)) {System.out.println(存款成功);
}
3.2 自旋开销CPU的空转危机
当多个线程激烈竞争时CAS可能导致CPU空转。优化策略 自适应自旋JVM动态调整自旋次数 pause指令插入CPU提示指令降低功耗 // x86架构实现示例
__asm__ volatile (pause); 退避策略随机等待后再重试
3.3 多变量原子性关联操作的困局
需要保证多个变量的原子更新时
方案一对象包装
class Account {int balance;int version;
}AtomicReferenceAccount atomicAccount new AtomicReference();
方案二锁机制
synchronized(lock) {account.balance - amount;account.version;
}
四、CAS应用场景分析
场景适用性示例计数器★★★★★AtomicInteger状态标志★★★★★AtomicBoolean对象引用更新★★★★☆AtomicReference复杂数据结构★★☆☆☆ConcurrentHashMap内部实现事务性操作★☆☆☆☆需要结合其他机制
五、性能对比CAS vs 锁
通过JMH基准测试ops/ms
线程数 CAS 同步锁 ReentrantLock1 15234 14567 142304 12345 2345 45668 9876 1023 2348 结论 低竞争场景性能相近 高并发场景CAS性能优势明显 极端竞争可能需要退化为锁机制