Java中的CAS

墨蓝 2023-06-01 06:23 78阅读 0赞

​ Java中的CAS

CAS全称 Compare And Swap(比较与交换),是一种无锁算法。在不使用锁(没有线程被阻塞)的情况下实现多线程之间的变量同步,java.util.concurrent包中的原子类就是通过CAS来实现了乐观锁。

基本介绍

CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。否则,处理器不做任何操作。

使用场景

有的时候我们需要对变量进行操作,如果是多线程,则有可能达不到我们的预期结果,Synchronized等关键字,可以解决问题,但是Synchronized关键字会让没有得到锁资源的线程进入BLOCKED状态,而后在争夺到锁资源后恢复为RUNNABLE状态,这个过程中涉及到操作系统用户模式内核模式的转换,代价比较高。这个时候我们就可以使用Atomic的一些原子操作来进行。

  1. public class CASTest {
  2. public static volatile int count = 0;
  3. public static AtomicInteger atomicCount = new AtomicInteger();
  4. public static void main(String[] args) throws InterruptedException {
  5. for (int i = 0; i < 2; i ) {
  6. new Thread(() -> {
  7. for (int j = 0; j < 10000; j ) {
  8. count ;
  9. atomicCount.incrementAndGet();
  10. }
  11. System.out.println("count end!");
  12. }).start();
  13. }
  14. Thread.sleep(2000);
  15. System.out.println(count);
  16. System.out.println(atomicCount.get());
  17. }
  18. }

来看一下这个的代码输出

  1. count end!
  2. count end!
  3. 18003
  4. 20000

可以看到volatile也没有办法保证运算的原子性。AtomicInteger使用CAS操作,可以保证运算的原子性。

AtomicInteger的实现原理

我们可以看一下AtomicInteger中incrementAndGet()的源码

  1. public final int incrementAndGet() {
  2. return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
  3. }

其是通过Unsafe来实现的,我们进入Unsafe中的getAndInt()方法中

  1. public final int getAndAddInt(Object var1, long var2, int var4) {
  2. int var5;
  3. do {
  4. var5 = this.getIntVolatile(var1, var2);
  5. } while(!this.compareAndSwapInt(var1, var2, var5, var5 var4));
  6. return var5;
  7. }

compareAndSwapInt是本地的方法,是通过CPU的cmpxchg指令,去比较寄存器中的 A 和 内存中的值 V。如果相等,就把要写入的新值 B 存入内存中。如果不相等,就将内存值 V 赋值给寄存器中的值 A。然后通过Java代码中的while循环再次调用cmpxchg指令进行重试,直到设置成功为止。

CAS存在的问题

  1. ABA问题CAS需要在操作值的时候检查内存值是否发生变化,没有发生变化才会更新内存值。但是如果内存值原来是A,后来变成了B,然后又变成了A,那么CAS进行检查时会发现值没有发生变化,但是实际上是有变化的。ABA问题的解决思路就是在变量前面添加版本号,每次变量更新的时候都把版本号加一,这样变化过程就从“A-B-A”变成了“1A-2B-3A”。JDK从1.5开始提供了AtomicStampedReference类来解决ABA问题。
  2. 并发高循环时间长的时候开销大CAS操作如果长时间不成功,会导致其一直自旋,给CPU带来非常大的开销。
  3. 只能保证一个共享变量的原子操作对一个共享变量执行操作时,CAS能够保证原子操作,但是对多个共享变量操作时,CAS是无法保证操作的原子性的。

    Java从1.5开始JDK提供了AtomicReference类来保证引用对象之间的原子性,可以把多个变量放在一个对象里来进行CAS操作。

参考

https://tech.meituan.com/2018/11/15/java-lock.html

关注公众号:蜜蜂技术巢了解更多知识
在这里插入图片描述

发表评论

表情:
评论列表 (有 0 条评论,78人围观)

还没有评论,来说两句吧...

相关阅读

    相关 JavaCAS

    ​ Java中的CAS > CAS全称 Compare And Swap(比较与交换),是一种无锁算法。在不使用锁(没有线程被阻塞)的情况下实现多线程之间的变量同步,java

    相关 javaCAS原理

    一、什么是CAS?     在计算机科学中,比较和交换(Conmpare And Swap)是用于实现多线程同步的原子指令。 它将内存位置的内容与给定值进行比较,只有在相

    相关 JavaCAS详解

    在JDK 5之前Java语言是靠synchronized关键字保证同步的,这会导致有锁 锁机制存在以下问题: (1)在多线程竞争下,加锁、释放锁会导致比较多的上下文切换和调

    相关 javaCAS

      本篇的思路是先阐明无锁执行者CAS的核心算法原理然后分析Java执行CAS的实践者Unsafe类,该类中的方法都是native修饰的,因此我们会以说明方法作用为主介绍Uns

    相关 JavaCAS详解

    在JDK 5之前Java语言是靠synchronized关键字保证同步的,这会导致有锁. 锁机制存在以下问题: (1)在多线程竞争下,加锁、释放锁会导致比较多的上下文

    相关 JavaCAS

    CAS的无锁思想 众所周知,Java中对并发控制的最常见方法就是锁,锁能保证同一时刻只能有一个线程访问临界区的资源,从而实现线程安全。然而,锁虽然有效,但采用的是一种悲观