1.CAS是什么?
CAS(Compare-and-Swap)是一种乐观锁的实现方式,全称为“比较并交换”,是一种无锁的原子操作。线程执行的时候不会加锁,它会假设此时没有冲突,然后完成某项操作;如果因为冲突失败了就重试,直到成功为止。
2.比较并交换的过程:
在 CAS 中有这样三个值:V:要更新的变量(var); E:预期值(旧值)(expected); N:新值(new)
修改之前,判断 V 是否等于 E,如果等于,将 V 的值设置为 N;
如果不等,说明已经有其它线程更新了 V,于是当前线程放弃更新,什么都不做。
3.CAS 有什么问题?如何解决?
① ABA 问题
如果一个位置的值原来是 A,后来被改为 B,再后来又被改回 A,那么进行 CAS 操作的线程将无法知晓该位置的值在此期间已经被修改过。
对于该问题,可以 使用版本号/时间戳 的方式来解决 ABA 问题。比如说,每次变量更新时,不仅更新变量的值,还更新一个版本号。CAS 操作时不仅要求值匹配,还要求版本号匹配。
② 循环性能开销
自旋 CAS,如果一直循环执行,一直不成功,会给 CPU 带来非常大的执行开销。
对于该问题,在 Java 中,很多使用自旋 CAS 的地方,会有一个自旋次数的限制,超过一定次数,就停止自旋。
③只能保证一个变量的原子操作
CAS 保证的是对一个变量执行操作的原子性,如果对多个变量操作时,CAS 目前无法直接保证操作的原子性的。
对于该问题,可以考虑改用锁来保证操作的原子性
可以考虑合并多个变量,将多个变量封装成一个对象,通过 AtomicReference 来保证原子性。
4.什么时候用乐观锁?
乐观锁多用于“读多写少“的环境,避免频繁加锁影响性能;
悲观锁多用于”写多读少“的环境,避免频繁失败和重试影响性能。
【如有错误或补充见解,欢迎留言交流和指正】