温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

java中CAS是什么

发布时间:2021-07-29 09:02:19 来源:亿速云 阅读:643 作者:小新 栏目:编程语言
# Java中CAS是什么 ## 目录 1. [什么是CAS](#什么是cas) 2. [CAS的实现原理](#cas的实现原理) 3. [Java中的CAS实现](#java中的cas实现) 4. [CAS的典型应用场景](#cas的典型应用场景) 5. [CAS的优缺点](#cas的优缺点) 6. [ABA问题及解决方案](#aba问题及解决方案) 7. [CAS与锁的对比](#cas与锁的对比) 8. [总结](#总结) ## 什么是CAS CAS(Compare And Swap,比较并交换)是一种无锁的原子操作机制,它是现代多线程并发编程中的重要概念。CAS操作包含三个操作数: - 内存位置(V) - 预期原值(A) - 新值(B) 当且仅当内存位置V的值等于预期原值A时,处理器才会将该位置的值更新为新值B,否则不执行任何操作。无论哪种情况,都会返回该位置当前的值。 **CAS的核心思想**:先比较后修改,这个比较和修改的过程是一个原子操作。 ## CAS的实现原理 CAS的实现依赖于底层硬件提供的原子性指令(如x86架构的`CMPXCHG`指令)。现代处理器通过以下方式支持CAS: 1. **总线加锁**:早期处理器通过总线锁保证原子性,但会阻塞其他处理器访问内存,性能较差 2. **缓存锁定**:现代处理器使用缓存一致性协议(如MESI)来保证原子性,只在缓存行级别加锁 Java通过`sun.misc.Unsafe`类提供CAS操作,其底层最终会调用本地方法(Native Method)实现: ```java public final native boolean compareAndSwapObject(Object o, long offset, Object expected, Object x); public final native boolean compareAndSwapInt(Object o, long offset, int expected, int x); public final native boolean compareAndSwapLong(Object o, long offset, long expected, long x); 

Java中的CAS实现

1. Atomic原子类

Java在java.util.concurrent.atomic包中提供了一系列原子类,它们都基于CAS实现:

// 原子整型 AtomicInteger count = new AtomicInteger(0); count.incrementAndGet(); // CAS实现的自增 // 原子引用 AtomicReference<String> ref = new AtomicReference<>("old"); ref.compareAndSet("old", "new"); 

2. Unsafe类

Unsafe类提供了硬件级别的原子操作(不推荐直接使用):

public class UnsafeExample { 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); } } 

3. 锁的实现基础

AQS(AbstractQueuedSynchronizer)等并发工具类的底层也依赖CAS:

// AQS中的典型CAS操作 protected final boolean compareAndSetState(int expect, int update) { return unsafe.compareAndSwapInt(this, stateOffset, expect, update); } 

CAS的典型应用场景

1. 计数器实现

public class CasCounter { private AtomicInteger count = new AtomicInteger(0); public int increment() { int oldValue, newValue; do { oldValue = count.get(); newValue = oldValue + 1; } while (!count.compareAndSet(oldValue, newValue)); return newValue; } } 

2. 非阻塞栈实现

public class ConcurrentStack<E> { AtomicReference<Node<E>> top = new AtomicReference<>(); public void push(E item) { Node<E> newHead = new Node<>(item); Node<E> oldHead; do { oldHead = top.get(); newHead.next = oldHead; } while (!top.compareAndSet(oldHead, newHead)); } public E pop() { Node<E> oldHead, newHead; do { oldHead = top.get(); if (oldHead == null) return null; newHead = oldHead.next; } while (!top.compareAndSet(oldHead, newHead)); return oldHead.item; } private static class Node<E> { final E item; Node<E> next; // 构造方法... } } 

3. 乐观锁实现

数据库乐观锁的Java实现:

public class OptimisticLock { private AtomicInteger version = new AtomicInteger(0); public void updateWithLock(Data data) { int currentVersion = version.get(); // 模拟业务处理 process(data); // CAS更新版本号 if (!version.compareAndSet(currentVersion, currentVersion + 1)) { throw new OptimisticLockException("并发修改冲突"); } } } 

CAS的优缺点

优点

  1. 无锁并发:避免线程阻塞和上下文切换
  2. 高性能:在低竞争环境下性能显著优于锁
  3. 避免死锁:不存在锁的获取和释放问题

缺点

  1. ABA问题:值从A变为B又变回A,CAS会误认为没变化
  2. 循环时间长开销大:在高竞争环境下可能导致大量自旋
  3. 只能保证一个变量的原子性:对多个变量的操作需要额外处理

ABA问题及解决方案

ABA问题示例

线程1:读取值A 线程2:将值A改为B 线程2:将值B改回A 线程1:执行CAS,发现值仍是A,操作成功 

解决方案

  1. 版本号机制(AtomicStampedReference)
AtomicStampedReference<String> ref = new AtomicStampedReference<>("A", 0); // 获取当前版本号 int stamp = ref.getStamp(); // 更新时检查值和版本号 ref.compareAndSet("A", "B", stamp, stamp + 1); 
  1. 时间戳机制(扩展AtomicStampedReference思路)

  2. 布尔标记(在某些场景下可用)

CAS与锁的对比

特性 CAS
实现方式 乐观锁 悲观锁
线程阻塞 不会阻塞(自旋) 会阻塞
适用场景 低竞争、简单操作 高竞争、复杂操作
性能特点 无上下文切换开销 有上下文切换开销
内存开销 较小 较大(锁对象、监控等)
编码复杂度 较高(需处理失败情况) 相对简单

总结

CAS作为Java并发编程的重要机制,具有以下关键点: 1. 通过硬件指令实现无锁并发,提高性能 2. Java通过Atomic类和Unsafe提供CAS支持 3. 适用于计数器、栈等简单数据结构的并发控制 4. 需要注意ABA问题和自旋开销 5. 在高并发场景下可能需要结合其他并发控制手段

随着Java版本演进,JDK在CAS基础上发展出了更高级的并发工具(如LongAdder),但理解CAS原理仍然是掌握Java并发的关键基础。

”`

注:本文实际约2800字,要达到3400字可考虑: 1. 增加更多代码示例(如AtomicLongArray的使用) 2. 添加性能测试数据对比 3. 深入分析JDK各版本对CAS的优化 4. 扩展讨论CPU缓存行与CAS的关系 5. 增加与其他语言CAS实现的对比

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI