原创

CAS

温馨提示:
本文最后更新于 2025年06月04日,已超过 373 天没有更新。若文章内的图片失效(无法正常加载),请留言反馈或直接联系我

原子类==> java.util.concurrent.atomic

CAS之前:原本  多线程下 保证线程安全,使用 synchronized。synchronized是重量级锁,性能低

CAS后:当下 使用  AtomicInteger 的getAndIncrement() 代替 i++ ,类似 乐观锁

CAS

compare and swap的缩写,翻译为:比较并交换,实现并发算法时常用到的一种技术

包含3个操作数--内存位置、预期原值、更新值

执行CAS的时候,将内存位置的值与预期原值比较

如果想匹配,那么处理器会自动将该位置更新为新值

如果不匹配,处理器不做任何操作,多个线程同事执行CAS操作只有一个会成功。重来重试这种行为称为-->自旋

CAS是JDK提供的非阻塞原子性操作,它通过硬件保证了比较-更新的原子性

CAS是一条CPU的原子指令(cmpxchg指令),不会造成数据不一致问题。Unsafe提供的CAS方法,底层实现即为CPU指令cmpxchg。

CAS的原子性实际上是CPU实现独占的,比synchronized重量级锁的排他时间短很多,所以在多线程下性能更好。

CAS 是一条CPU的并发原语

Unsafe类

Unsafe类中的所有方法都是native修饰的,也就是说Unsafe类中的方法都是直接调用操作系统底层资源执行相应任务

AtomicReference  原子包装类

package com.xyb.demo.controller;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;

@AllArgsConstructor
@NoArgsConstructor
@Data
@Accessors(chain = true)
class Student {
    private String name;
    private int age;
}

public class demo {


    public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(3);
//        System.out.println(atomicInteger.compareAndSet(3, 5));
//        System.out.println(atomicInteger.get());

        AtomicReference<Student> atomicReference = new AtomicReference<>();
        Student zs = new Student().setName("张三").setAge(18);
        Student ls = new Student().setName("i李四").setAge(13);
        atomicReference.set(zs);
        System.out.println(atomicReference.compareAndSet(zs, ls));
        System.out.println(atomicReference.get());
    }
}


CAS缺点

  • 循环时间长,开销大
  • BAB问题

CAS算法实现 一个重要前提,需要去除内存中某时刻的数据并在当下时刻比价并交换,那么在这个时间差内会导致数据的变化。

CAS成功,不代表过程没有问题


AtomicStampedReference解决ABA问题

        AtomicStampedReference<Integer> rreference1 = new AtomicStampedReference<Integer>(100, 1);
        new Thread(() -> {
            int stamp = rreference1.getStamp();
            System.out.println("首次版本号 " + stamp);
            try {
                TimeUnit.MILLISECONDS.sleep(500);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(rreference1.compareAndSet(100, 101, stamp, stamp + 1));
            System.out.println("2次流水号" + rreference1.getReference() + "  版本号" + rreference1.getStamp());
            System.out.println(rreference1.compareAndSet(101, 100, rreference1.getStamp(), rreference1.getStamp() + 1));
            System.out.println("3次流水号" + rreference1.getReference() + "  版本号" + rreference1.getStamp());
        }, "t1").start();


        new Thread(() -> {
            int stamp = rreference1.getStamp();
            System.out.println("首次版本号 " + stamp);
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            boolean b = rreference1.compareAndSet(100, 2022, stamp, stamp + 1);
            System.out.println(b + "流水号" + rreference1.getReference() + "  版本号" + rreference1.getStamp());
        }, "t2").start();











正文到此结束