CAS简单的说,CAS需要你额外给出一个期望值(主内存中的现有值),也就是你认为这个变量现在应该是什么样子的;如果变量不是你想象的那样,那说明它已经被别人修改过了;你就要重新读取,再次尝试修改就好了。
(1)与锁相比,使用比较交换(下文简称CAS)会使程序看起来更加复杂一些。但由于其非阻塞性,它对死锁问题天生免疫,并且,线程间的相互影响也远远比基于锁的方式要小。更为重要的是,使用无锁的方式完全没有锁竞争带来的系统开销,也没有线程间频繁调度带来的开销,因此,它要比基于锁的方式拥有更优越的性能。
(2)无锁的好处:
第一,在高并发的情况下,它比有锁的程序拥有更好的性能;
第二,它天生就是死锁免疫的。
就凭借这两个优势,就值得我们冒险尝试使用无锁的并发。
(3)CAS算法的过程是这样:它包含三个参数CAS(V,E,N): V表示原有的值,E表示预期值,N表示新值。仅当V值等于E值时,才会将V的值设为N,如果V值和E值不同,则说明已经有其他线程做了更新,则当前线程什么都不做。最后,CAS返回当前V的真实值。
CAS操作是抱着乐观的态度进行的(乐观锁),它总是认为自己可以成功完成操作;当多个线程同时使用CAS操作一个变量时,只有一个会胜出,并成功更新,其余均会失败;失败的线程不会被挂起,仅是被告知失败,并且允许再次尝试,当然也允许失败的线程放弃操作;基于这样的原理,
Cas ABA的问题Cas主要检查 内存值V与旧的预值值=E是否一致,如果一致的情况下,则修改。
这时候会存在ABA的问题:
如果将原来的值A,改为了B,B有改为了A 发现没有发生变化,实际上已经发生了变化,所以存在Aba问题。
解决办法:通过版本号码,对每个变量更新的版本号码做+1
--- 和预期值概念一样只不过是每修改成功一次后就将版本号递增+1;
CAS锁参数CAS(V,E,N)分别是value、expect、new的缩写
V:原有的值(存放在共享主内存中);
E:预期值(存放在当前线程的工作内存中)也就是说你认为原有值V是多少,后期会那E和V做比较,相等的话表示获取到了锁;
N:新值;
判断V==E:
如果不等于就表示主内存原有V值已被修改,需要重新获取预期值重新判断;
如果等于就表示主内存没有被其它线程操作过,将N新值替换到V原有值中。
CAS底层通过unsafe实现
- Java是通过unsafe jni技术调用C代码从而实现的CAS
- 原子类/自增类:AtomicInteger,AtomicLong,AtomicBoolean等都是使用 CAS 实现。
说明:unsafe类提供了专门用于原子性相关的标准方法,手写CAS也通过unasfe实现。
AtomicInteger这些也都是调用的unsafe实现的原子递增。
原子类
使用AtomicInteger实现自增
public class Test002 extends Thread {
// AtomicLong原子类默认从0开始
private static AtomicLong atomicLong = new AtomicLong();
@Override
public void run() {
while (atomicLong.get() < 10000) {
// 递增+1
long l = atomicLong.incrementAndGet();
System.out.println(Thread.currentThread().getName() + "," + l);
}
}
public static void main(String[] args) throws InterruptedException {
Long startTime=System.currentTimeMillis();
Test002 t1 = new Test002();
Test002 t2 = new Test002();
t1.start();
t2.start();
t1.join();
t2.join();
Long endTime=System.currentTimeMillis();
System.out.println(endTime-startTime);
}
}
atomicLong.incrementAndGet();递增方法源码查看
public class Test002 extends Thread {
// AtomicLong原子类默认从0开始
private static AtomicLong atomicLong = new AtomicLong();
@Override
public void run() {
while (atomicLong.get() < 10000) {
// 递增+1
long l = atomicLong.incrementAndGet();
System.out.println(Thread.currentThread().getName() + "," + l);
}
}
public static void main(String[] args) throws InterruptedException {
Long startTime=System.currentTimeMillis();
Test002 t1 = new Test002();
Test002 t2 = new Test002();
t1.start();
t2.start();
t1.join();
t2.join();
Long endTime=System.currentTimeMillis();
System.out.println(endTime-startTime);
}
}
atomicLong.incrementAndGet();递增方法源码查看
atomicLong.incrementAndGet()调用getAndAddLong方法进行递增,
// var1=内存值、var6=旧的预期值 、var4=1
CAS(V, E, N) 三个参数对应关系:
var1 = V 内存值
var6 = E 旧的预期值
var6 + var4 = N 修改的新值
// var1=内存值、var6=旧的预期值 、var4=新值
// cas判断:var1==var6?var=var4:已被修改重新自旋
public final long getAndAddLong(Object var1, long var2, long var4) {
long var6;
// 进行CAS自旋-循环
do {
// 获取旧的预期值
var6 = this.getLongVolatile(var1, var2);
} while(!this.compareAndSwapLong(var1, var2, var6, var6 + var4));
// 返回内存值
return var6;
}
基于Atomic原子类实现CAS无锁
public class AtomicTryLock {
private volatile AtomicInteger atomicInteger = new AtomicInteger(0);
// 记录当前线程,只有当前线程才可释放锁
private Thread lockCurrentThread;
public boolean tryLock() {
// compareAndSet(期望值, 修改值)
boolean result = atomicInteger.compareAndSet(0, 1);
if (result) {
lockCurrentThread = Thread.currentThread();
}
return result;
}
public boolean unLock() {
if (lockCurrentThread != null && lockCurrentThread != Thread.currentThread()) {
return false;
}
return atomicInteger.compareAndSet(1, 0);
}
// 测试
public static void main(String[] args) {
// 创建自定义的锁
AtomicTryLock atomicTryLock = new AtomicTryLock();
// for循环创建10个线程
IntStream.range(1, 10).forEach((i) -> new Thread(() -> {
try {
// 获取锁
boolean result = atomicTryLock.tryLock();
if (result) {
System.out.println(Thread.currentThread().getName() + ",获取锁成功~");
} else {
System.out.println(Thread.currentThread().getName() + ",获取锁失败~");
}
} catch (Exception e) {
e.printStackTrace();
atomicTryLock.unLock();
} finally {
// 释放锁
atomicTryLock.unLock();
}
}).start());
}
}



