一、CAS
1、什么是CAS
- 概念:假设多个线程操作共享资源时不会发生并发冲突,只是在最后更新共享资源的时候判断一下在此期间有没有别的线程修改了这个共享资源。如果发生冲突就重试,直到没有冲突,更新成功。CAS就是一种类似乐观锁实现方式。
2、代码演示
- CAS compareAndSet : 比较并交换!
public class CASTest {
public static void main(String[] args) {
AtomicInteger atomicInteger = new AtomicInteger(2020);
//源码分析
// public final boolean compareAndSet(int expect, int update);
//如果我期望的值达到了,那么就更新,输出true,否则,就不更新,输出false。 CAS 是CPU的并发原语
System.out.println(atomicInteger.compareAndSet(2020, 2021));
System.out.println(atomicInteger.get());
//加一操作
System.out.println(atomicInteger.getAndIncrement());
System.out.println("第二次----->"+atomicInteger.get());
System.out.println("第二次----->"+atomicInteger.compareAndSet(2022, 2023));
}
}
运行结果:
3、Unsafe类
二、ABA问题
- 共享内存变量的数据为1时,A线程想取到此变量为1时进行操作,但B线程在此之前进行了两次CAS操作,虽然最后共享变量还是为1,但是已经不是最初的那个变量1了,而此时A线程却不知道B线程的此操作,这就是ABA问题。
- 代码演示
public class ABATest {
public static void main(String[] args) {
AtomicInteger atomicInteger = new AtomicInteger(2020);
//B线程的第一次CAS操作
System.out.println("B线程的第一次CAS操作---->"+atomicInteger.compareAndSet(2020, 2021));
System.out.println("B线程第一次打印---->"+atomicInteger.get());
//B线程的第二次CAS操作
System.out.println("B线程的第二次CAS操作---->"+atomicInteger.compareAndSet(2021, 2020));
System.out.println("B线程第二次打印---->"+atomicInteger.get());
//正常操作的A线程
System.out.println("A线程正常操作---->"+atomicInteger.compareAndSet(2020,2021));
System.out.println("A线程正常操作---->"+atomicInteger.get());
}
}
- 运行结果:
三、原子引用
1、代码演示
public class CASAndABA {
//类似于乐观锁,可以有一个初始对应的版本号1
static AtomicStampedReference atomicStampedReference=new AtomicStampedReference(1,1);
public static void main(String[] args) {
//线程B两次进行CAS操作
new Thread(()->{
//获取当前的版本号
int stamp = atomicStampedReference.getStamp();
System.out.println("B线程进行CAS操作前的版本号----->"+stamp);
try{
TimeUnit.SECONDS.sleep(2);
}catch (Exception e){
e.printStackTrace();
}
//B线程进行第一次CAS操作
System.out.println("B线程第一次进行CAS操作------>"+atomicStampedReference.compareAndSet(
1,
2,
atomicStampedReference.getStamp(), //得到最新的版本号
atomicStampedReference.getStamp() + 1));
System.out.println("B线程第一次打印版本号------>"+atomicStampedReference.getStamp());
//B线程进行第二次CAS操作
System.out.println("B线程第二次进行CAS操作------>"+atomicStampedReference.compareAndSet(
2,
1,
atomicStampedReference.getStamp(),
atomicStampedReference.getStamp() + 1));
System.out.println("B线程第二次打印版本号------>"+atomicStampedReference.getStamp());
},"线程B").start();
//线程A进行CAS操作
new Thread(()->{
//获得当前版本号
int stamp = atomicStampedReference.getStamp();
System.out.println("A线程进行CAS操作前的版本号----->"+stamp);
try{
TimeUnit.SECONDS.sleep(2);
}catch (Exception e){
e.printStackTrace();
}
System.out.println("A线程第一次进行CAS操作------>"+atomicStampedReference.compareAndSet(
1,
3,
atomicStampedReference.getStamp(),
atomicStampedReference.getStamp() + 1));
System.out.println("A线程第一次打印版本号------>"+atomicStampedReference.getStamp());
},"A线程").start();
}
}
- 运行结果: