一、什么是CAS?
CAS全名是Compare And Swap(比较与替换),它是用来解决高并发问题的一种方案。实现的原理大致上就是先将需要修改的变量V读取到变量E中缓存起来,然后在写入新变量U的时候将E和重新读取出来的V变量比较一遍,如果两者一致则把U写入V中,不一致则表明期间有其它线程修改了属性,然后进行自旋重新走一遍流程,直到修改操作执行完成。
可以将CAS看作是(数据库)乐观锁的一种简化实现版本
二、CAS的优缺点
优点:
- 它是一个无锁操作,所以在并发量不是很高的情况下可以极大的减小加锁带来的时间消耗
缺点:
- 它无法解决ABA问题,就是在修改期间有线程将之改变后又改回去的情况下,它是没有办法做出判断并记录操作的。这对一些流水记录操作业务的情景不太友好;
- 由于CAS是通过自旋实现的,所以如果多次更新不成功,那么其他线程不停的执行读取操作所造成的性能开销比较大;
- CAS只能保证一个变量的原子性操作,不能保证代码块的原子性;
三、CAS的简单实现
CAS在jdk中有自己的实现,它主要是在Unsafe这个类中,下面有一段简单实现代码:
工具类:
package com.muyichen.demo.cas;
import lombok.Data;
import org.springframework.objenesis.instantiator.util.UnsafeUtils;
import sun.misc.Unsafe;
@Data
public class CASLock {
private volatile int state;
private static Unsafe unsafe;
private static Long offSet;
static {
unsafe = UnsafeUtils.getUnsafe();
try {
offSet = unsafe.objectFieldOffset(CASLock.class.getDeclaredField("state"));
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
public boolean cas() {
return unsafe.compareAndSwapInt(this, offSet, 0, 1);
}
}
测试类:
package com.muyichen.demo.cas;
import org.springframework.objenesis.instantiator.util.UnsafeUtils;
import sun.misc.Unsafe;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
public class CASTest {
private volatile static int sum = 0;
/**
* 直接使用原子类进行操作
*/
private static AtomicInteger sums = new AtomicInteger();
/**
* 使用synchronized加锁
*/
static Object object = "";
/**
* 使用Lock加锁
*/
static ReentrantLock lock = new ReentrantLock();
/**
* 使用CAS
*/
static CASLock casLock = new CASLock();
public static void main(String[] args) throws InterruptedException {
// Entity entity = new Entity();
//
// Unsafe unsafe = UnsafeUtils.getUnsafe();
//
// // 12表示偏移量:8位对象头+4位压缩指针;0表示对比值,1表示修改值
// unsafe.compareAndSwapInt(entity, 12, 0, 1);
// System.out.println(entity.getX());
//
// unsafe.compareAndSwapInt(entity, 12, 1, 3);
// System.out.println(entity.getX());
//
// unsafe.compareAndSwapInt(entity, 12, 1, 5);
// // 这次修改由于x的值已经是3了,所以修改不成功
// System.out.println(entity.getX());
long millis = System.currentTimeMillis();
CountDownLatch latch = new CountDownLatch(10);
// for (int i = 0; i < 10; i++) {
// Thread thread = new Thread(() -> {
// synchronized (object) {
// for (int j = 0; j < 10000; j++) {
// sum++;
// }
// latch.countDown();
// }
// });
// thread.start();
// }
// for (int i = 0; i < 10; i++) {
// Thread thread = new Thread(() -> {
// lock.lock();
// try {
// for (int j = 0; j < 10000; j++) {
// sum++;
// }
// } finally {
// lock.unlock();
// latch.countDown();
// }
// });
// thread.start();
// }
for (int i = 0; i < 10; i++) {
Thread thread = new Thread(() -> {
for (;;) {
if (casLock.getState() == 0&&casLock.cas()) {
for (int j = 0; j < 10000; j++) {
sum++;
}
casLock.setState(0);
latch.countDown();
break;
}
}
});
thread.start();
}
latch.await();
System.out.println("执行耗时:" + (System.currentTimeMillis() - millis));
System.out.println(sum);
}
}