CAS
compareAndSet 比较并交换
public class CASTest {
public static void main(String[] args) {
AtomicInteger atomicInteger = new AtomicInteger(2020);
//期望、更新
// public final boolean compareAndSet(int expect, int update)
//如果我的期望值达到了,就更新;没达到,就不更新
System.out.println(atomicInteger.compareAndSet(2020, 2021));
System.out.println(atomicInteger.get());
System.out.println(atomicInteger.compareAndSet(2020, 2021));
System.out.println(atomicInteger.get());
}
}
测试结果:
true
2021
false
2021
CAS: 比较当前工作内存中的值和主内存中的值,如果这个值是期望的,那么则执行操作;如果不是则一直循环
缺点:
- 循环会耗时
- 一次性只能保证一个共享变量的原子性
- ABA问题
ABA问题: 就是两个线程要操作主存中的一个变量,主存中有一个num = 0;线程一期望num=0,修改为1,但在线程一拿到主存的num之前,线程二先拿到了主存中的数据,线程二做了两个操作,先是期望num=0,修改为3,然后又把num改回了0。这个时候线程1来拿主存中的num,发现num=0,符合他的预期,就进行了修改,但是他并不知道这个num = 0已经被别人动过了,不是最开始的0了,是经过别人修改后返回的0。
怎么解决ABA问题呢? 原子引用
原子引用
public class ABATest {
public static void main(String[] args) {
AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<Integer>(1,1);
int stamp = atomicStampedReference.getStamp();
System.out.println("初始时间戳"+stamp);
new Thread(()->{
System.out.println("a首次获取时间戳"+atomicStampedReference.getStamp());
System.out.println(atomicStampedReference.compareAndSet(1, 2, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1));
System.out.println("a操作一次时间戳"+atomicStampedReference.getStamp());
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(atomicStampedReference.compareAndSet(2, 1, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1));
System.out.println("a操作二次时间戳"+atomicStampedReference.getStamp());
},"a").start();
new Thread(()->{
System.out.println(atomicStampedReference.compareAndSet(1, 6, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1));
System.out.println("b操作一次时间戳"+atomicStampedReference.getStamp());
},"b").start();
}
}
执行结果:
初始时间戳1
a首次获取时间戳1
true
a操作一次时间戳2
false
b操作一次时间戳2
true
a操作二次时间戳3