什么是CAS
Unsafe 类
打断点发现this + 偏移量 不等 var5
则不自增,返回 var5
自旋锁:
CAS : ABA 问题:(狸猫换太子)
CAS : 比较当前工作内存中的值和主内存中的值,如果这个值是期望的,那么则执行操作,否则不执行!如果不是则一直循环
优点:自带原子性
缺点:循环比较耗时,一次性只能保证一个g共享变量的原子性,ABA 问题
ABA 问题
左边A 线程,右边B线程,B线程将1 期望值改为3,又将 3 改为1 ,A 最终还是1 ,但是 左边A 线程看到的值还是A =1
package com.cas;
import java.util.concurrent.atomic.AtomicInteger;
public class CASDemo {
//CAS 缩写就是compareAndSet : 比较并交换!
public static void main(String[] args) {
//对于我们平时写的SQL: 乐观锁
AtomicInteger atomicInteger = new AtomicInteger(2020);
//CAS
//期望,更新
//public final boolean compareAndSet(int expect,int update)
//如果我期望的值达到了,那么就更新,否则,就不更新,CAS 是CPU 的并发原语!
//=======捣乱的线程==
System.out.println(atomicInteger.compareAndSet(2020, 2021));
System.out.println(atomicInteger.get());
System.out.println(atomicInteger.compareAndSet(2021, 2020));
System.out.println(atomicInteger.get());
//====期望的线程===
System.out.println(atomicInteger.compareAndSet(2020, 2021));
System.out.println(atomicInteger.get());
// System.out.println(atomicInteger.getAndIncrement());
//如果再设置一次能期望成功吗
// System.out.println(atomicInteger.compareAndSet(2020, 2021));
// System.out.println(atomicInteger.get());
}
}
如何就觉ABA 问题?
用原子引用解决
原子引用
解决ABA 问题,引用原子引用!对应的思想! 就是乐观锁!
带版本号 的原子操作
注意:正常在业务操作,这里面比较的都是对象,
package com.cas;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicStampedReference;
public class CASDemo {
//CAS 缩写就是compareAndSet : 比较并交换!
public static void main(String[] args) {
//对于我们平时写的SQL: 乐观锁
//AtomicInteger atomicInteger = new AtomicInteger(2020);
//参数:初始值,版本号
//AtomicStampedReference 注意:如果泛型是一个包装类,注意对象的引用问题
AtomicStampedReference<Integer> atomicInteger = new AtomicStampedReference<>(1,1);
new Thread(()->{
int stamp =atomicInteger.getStamp(); //获得版本号
System.out.println("a1=>"+stamp);
try {
TimeUnit.SECONDS.sleep(2);
} 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, stamp + 1));
System.out.println("b1=>"+atomicInteger.getStamp());
},"B").start();
// //CAS
// //期望,更新
// //public final boolean compareAndSet(int expect,int update)
// //如果我期望的值达到了,那么就更新,否则,就不更新,CAS 是CPU 的并发原语!
// //=======捣乱的线程==
// System.out.println(atomicInteger.compareAndSet(2020, 2021));
// System.out.println(atomicInteger.get());
//
// System.out.println(atomicInteger.compareAndSet(2021, 2020));
// System.out.println(atomicInteger.get());
//
// //====期望的线程===
// System.out.println(atomicInteger.compareAndSet(2020, 2021));
// System.out.println(atomicInteger.get());
//
// // System.out.println(atomicInteger.getAndIncrement());
// //如果再设置一次能期望成功吗
// // System.out.println(atomicInteger.compareAndSet(2020, 2021));
// // System.out.println(atomicInteger.get());
}
}
输出结果:
a1=>1
b1=>1
true
a2=>2
true
a3=>3
false
b1=>3
总结:原子引用解决ABA 问题