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 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 rreference1 = new AtomicStampedReference(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(); 正文到此结束
- 本文标签: Java
- 本文链接: http://119.91.109.247:8443//article/86
- 版权声明: 本文由张亚东原创发布,转载请遵循《署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)》许可协议授权