理解CAS
什么是CAS
public class CASDemo {
//CAS compareAndSet:比较并交换
public static void main(String[] args) {
AtomicInteger atomicInteger=new AtomicInteger(2020);
//期望,更新
/*public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}*/
//如果期望的值达到了,那么就更新,否则就不更新 CAS cpu的并发原因
System.out.println(atomicInteger.compareAndSet(2020, 2021));
System.out.println(atomicInteger.get());
atomicInteger.getAndIncrement();
System.out.println(atomicInteger.compareAndSet(2020, 2022));
System.out.println(atomicInteger.get());
}
}
CAS:比较当前工作内存中的值和主内存中的值,如果这个值是期望的,那么则执行操作(否则do while 即自旋锁)
缺点:
- 底层是自旋锁do while,循环是耗时
- 一次性只能保证一个共享变量的原子性
- ABA问题
Unsafe
ABA问题 狸猫换太子
public class CASDemo {
//CAS compareAndSet:比较并交换
public static void main(String[] args) {
AtomicInteger atomicInteger=new AtomicInteger(2020);
//对于我们平时写的sql来说 一般使用乐观锁来解决
//期望,更新
/*public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}*/
//如果期望的值达到了,那么就更新,否则就不更新 CAS cpu的并发原因
//==================捣乱线程==================//
System.out.println(atomicInteger.compareAndSet(2020, 2021));
System.out.println(atomicInteger.compareAndSet(2021, 2020));
System.out.println(atomicInteger.get());
//atomicInteger.getAndIncrement();
//==================期望线程==================//
System.out.println(atomicInteger.compareAndSet(2020, 2021));
System.out.println(atomicInteger.get());
}
}
解决ABA问题- 原子引用
带版本号的原子操作
public class CASDemo {
//CAS compareAndSet:比较并交换
public static void main(String[] args) {
//AtomicInteger atomicInteger=new AtomicInteger(2020);
//int Integer包装类有一个对象缓存机制 默认是-128~127,推荐使用静态工厂方法valueof获取对象实例,而不是new
//如果范围超过 -128~127 那么new一定会创建新的对象分配新的内存空间,这时比较就会比较的内存地址而不是值,所以会变为false
AtomicStampedReference atomicInteger=new AtomicStampedReference<>(1,1);
//注意:如果泛型是一个包装类,注意对象的引用问题
new Thread(()->{
int stamp = atomicInteger.getStamp(); //获得版本号 最初的期望版本号
System.out.println("a1=>"+atomicInteger.getStamp());
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
//version+1
System.out.println(atomicInteger.compareAndSet(1, 2, atomicInteger.getStamp(), atomicInteger.getStamp() + 1));
System.out.println("a2=>"+atomicInteger.getStamp());
System.out.println(atomicInteger.compareAndSet(2, 1, atomicInteger.getStamp(), atomicInteger.getStamp() + 1));
System.out.println("a3 =>"+atomicInteger.getStamp());
},"A").start();
new Thread(()->{
int stamp = atomicInteger.getStamp(); //获得版本号
System.out.println("b1=>"+atomicInteger.getStamp());
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(atomicInteger.compareAndSet(1, 6, stamp, atomicInteger.getStamp() + 1));
System.out.println("b2=>"+atomicInteger.getStamp());
},"B").start();
}
}
注意点