CAS 比较并交换 compareAndSwap。
CAS是一种乐观锁机制,也被称为无锁机制。全称:
Compare-And-Swap。它是并发编程中的一种原子操作,通常用于多线程环境下实现同步和线程安全。CAS操作通过比较内存中的值与期望值是否相等来确定是否执行交换操作。如果相等,则执行交换操作,否则不执行。由于CAS是一种无锁机制,因此它避免了使用传统锁所带来的性能开销和死锁问题,提高了程序的并发性能
判断内存中的某个值是否为期望值,如果是则更改为新值,这是个原子过程,如果不是这不更改。
CAS操作包括三个操作数:内存位置(V)、预期原值(A)和新值(B)。
当执行CAS操作时,只有当V的值等于A时,才会将V的值更新为B,否则不做任何操作。
CAS操作是原子性的,也就是说在同一时刻只能有一个线程执行CAS操作,因此CAS机制保证了数据的一致性。
底层原理:
1.自旋锁
2.unsafe类
unsafe类是rt.jar包的原生类。靠cpu指令原语
来保证原子性
自璇(源码):
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
//获取当前var1对象在内存地址var2的真实值
var5 = this.getIntVolatile(var1, var2);
//比较并交换(返回成功-true跳出循环,返回失败-false 继续自璇)
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
过程:
假设A/B两个线程同时执行getAndAddInt操作(分别跑在不同的cpu):
1.AtomicInteger里面value原始值是3,即主内存中的AtomicInteger的value为3,根据JMM模型线程AB各自持有一份值为3的value的副本分别到各自的工作内存
2.线程A 通过getIntVolatile(var1,var2)拿到value值3,这时线程A被挂起
3.线程B也通过getIntVolatile(var1,var2)获取到value值3 此时刚好线程B没有被挂起并执行compareAndSwap方法,比较内存值也为3,成功修改为4,B线程结束
4.A线程恢复执行compareAndSwapInt方法比较,发现自己手里的数字3和内存值4不一致,说明该值已经被其他线程修改过,那么A线程本次修改失败,只能重新读取重新来一遍
5.线程A重新获取value值,因为变量value被volatile修饰,所以其他线程对它修改,线程A总能看到线程A继续执行compareAndSwapInt进行比较替换,直达成功
1.自璇循环时间长,cpu开销大
2.只能保证一个共享变量的原子操作(cas只能保证一个对象,枷锁能保证一段代码的原子性)
3.ABA问题
ABA问题:
一个线程 1 从内存位置V 获取A值
这个时候线程2也从内存获取A值,并且线程2会进行操作将值改为B,然后线程2又将位置v的数据改成A,这时候线程1进行cas操作发现 内存中的值仍然是A,然后线程1操作成了。 线程1虽然操作成功了但是这个过程可能有问题
解决ABA问题:
加版本号
线程先拿版本号,再要修改的时候再把刚拿的版本号与现在的版本号对比,一致再修改。
AtomicStampedReference
在多线程执行 i++会出现线程安全问题, 使用AtomicInteger就可以避免
AtomicInteger atomicInteger = new AtomicInteger();
public void addMyAtomic(){
atomicInteger .getAndIncrement();
}