美文网首页
JUC(三)CAS与原子变量

JUC(三)CAS与原子变量

作者: NIIIICO | 来源:发表于2022-07-10 23:55 被阅读0次

一、CAS

1、CAS简介
  • CAS(compare and swap),比较并交换。
  • CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。
  • 如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。否则,处理器不做任何操作。
  • 通过CAS可以实现原子操作
2、ABA问题
  • 如果一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时会发现它的值没有发生变化,但是实际变化了。
  • ABA问题可以通过添加版本号来解决:1A-2B-3A。
3、乐观锁、悲观锁
  • 乐观锁认为每次修改数据时不会有人同时修改数据。执行更新时判断在此期间是否有人修改了数据,如果数据发生变动则放弃此次更新,否则执行更新。
  • 悲观锁认为每次修改数据时都会有人同时修改数据。执行更新时锁住数据,不允许其他人更新。
  • CAS属于乐观锁,Synchronized属于悲观锁。
4、CAS效率
CAS效率

从图中可以看出:
在单核系统中,CAS省去了锁升级、抢锁等过程;
在多核系统中,传统加锁会导致只有一条线程在执行任务,而CAS则可以多线程同时执行任务,提升效率。

注意:如果线程竞争比较大,由于其他线程更新失败,CAS会一直重试,导致CPU一直执行重复任务,浪费CPU资源,此时使用锁可能是个更好的选择。

二、原子变量

基于CAS操作,Java提供了一套API,在java.util.concurrent.atomic包下。常用的如:AtomicInteger、AtomicLong、AtomicBoolean等。原子变量是线程安全的。

AtomicInteger atomicInteger = new AtomicInteger(1);
// 以AtomicInteger为例,i++可以写成如下代码
atomicInteger.incrementAndGet();

分析一下AtomicInteger源码:

public class AtomicInteger extends Number implements java.io.Serializable {
    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
    // volatile修饰
    private volatile int value;

    public final int incrementAndGet() {
        return U.getAndAddInt(this, VALUE, 1) + 1;
    }
}

可以看到:
1、AtomicInteger中的value被volatile修饰,保证了可见性;
2、incrementAndGet通过Unsafe.getAndAddInt实现。

public class Unsafe {
    public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        do {
            //重新获取var5的值
            var5 = this.getIntVolatile(var1, var2);
        // 如果CAS更新失败,重复do中的代码
        } while (!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
        return var5;
    }

    // expected:期望值,update:目标值
    public final native boolean compareAndSwapInt(Object o, long offset, int expected,int update);
}

再看Unsafe的源码,getAndAddInt中,会通过CAS操作尝试更新,若更新失败,则会一直重试。

三、原子累加器

为了对多线程下大量自增操作进行优化,Java还提供了原子累加器:LongAdder。

原子累加器原理
伪共享问题

CPU为了效率,每次会将内存中的数据读取到高速缓冲区,高速缓冲区中的最小缓存单位是Cache Line,一般是64byte,一个long类型是8byte,因此一个缓存行可以存储8个long类型的变量。

于是可能出现如下问题:
1、我们想core1处理cell[0]的数据,core2处理cell[1]的数据;
2、由于读取了一行数据,导致core1、core2同时有cell[0]、cell[1]的数据;
3、因此当core1更新了cell[0]时,core2也需要从内存中重新读取数据,来保证数据的一致性。

当多线程修改互相独立的变量时,如果这些变量共享同一个缓存行,就会无意中影响彼此的性能,这就是伪共享

解决方法:java8提供@sun.misc.Contended注解

// LongAdder中的Cell便是使用@sun.misc.Contended注解来解决伪共享问题
@sun.misc.Contended static final class Cell {}
伪共享

相关文章

  • JUC(三)CAS与原子变量

    一、CAS 1、CAS简介 CAS(compare and swap),比较并交换。 CAS 操作包含三个操作数 ...

  • JUC

    1. Java JUC 简介 2. volatile 关键字-内存可见性 3. 原子变量-CAS算法 4. Con...

  • JUC(二) - 原子变量CAS算法

    2 原子变量CAS算法 CAS (Compare-And-Swap) 是一种硬件对并发的支持,针对多处理器操作而设...

  • [Java]重学Java-原子类

    JUC包下的原子类 JUC就是大名鼎鼎的java并发包,我们今天来看看基于非阻塞性算法的CAS封装的原子类.JUC...

  • JUC线程高级---原子变量与CAS算法

    **版权声明:本文为小斑马伟原创文章,转载请注明出处! CAS 算法:CAS (Compare-And-Swap)...

  • JUC系列02-原子变量与CAS算法

    1 何为原子变量(Atomic) 1 计算机中的Atomic是指不能分割的最小单位。2 JKD1.5之后java....

  • 使用CAS引发ABA问题

    由于CAS原子操作性能高,因此其在JUC包中被广泛引用,只不过如果使用得不合理,CAS原子操作就会存在ABA问题。...

  • Java中CAS原理分析(volatile和synchroniz

    CAS是什么? CAS英文解释是比较和交换,是cpu底层的源语,是解决共享变量原子性实现方案,它定义了三个变量,内...

  • 最简单的CAS机制说明

    CAS(Compare-And-Swap) 算法保证数据变量的原子性 CAS 算法是硬件对于并发操作的支持 CAS...

  • Java基础-线程 (三)-锁

    CAS是什么? 了解CAS之前,我们先了解变量的2大特性。 原子操作(原子性):对于操作A,要么执行完,要么完全不...

网友评论

      本文标题:JUC(三)CAS与原子变量

      本文链接:https://www.haomeiwen.com/subject/klmkjrtx.html