CAS是什么?
CAS是避免使用锁的基本机制之一。
CAS的原理是变量只在线程内的与从主存中获取的值相等时更新,且获取与更新是一个原子操作。整个操作不需要使用锁。
其中最重要的事是硬件必须支持CAS,以使其是一个真正的原子操作而且不需要使用锁。
Java 5.0引入了对CAS的底层支持,在 int、long 和对象的引用等类型上都公开了CAS操作,并且JVM把他们编译为底层硬件提供的最有效的方法。在支持CAS的平台上,运行时把它们编译为相应的指令。在不支持的平台上,那么JVM将使用自旋锁。在原子变量类中使用了这些底层的JVM支持为数字类型和引用类型提供一种高效的CAS操作.
原子变量将发生竞争的范围缩小到单个变量上,这是粒度最细的情况。更新原子变量的在非竞争的情况下不会比获取锁的非竞争情况慢,而它的竞争情况肯定比锁的竞争情况快,因为它不需要挂起和重新调度线程。
原子变量相当于一种泛化的 volatile 变量。
常用的原子变量有 AtomicInteger、AtomicLong、AtomicBoolean 以及 AtomicRefernce。
所有原子变量都支持CAS,此外 AtomicInteger和 AtomicLong 还支持算术运算。
应用场景
下面的代码是一个基于支持CAS操作的 AtomicInteger 实现的计数器:
public class SafeCounterWithoutLock {
private final AtomicInteger counter = new AtomicInteger(0);
public int count() {
return counter.get();
}
public void increment() {
counter.incrementAndGet();
}
}
测试:
private static final int N_TASKS = 1000;
private static final ExecutorService EXEC = Executors.newFixedThreadPool(9);
@Test
public void test() throws InterruptedException {
SafeCounterWithoutLock counter = new SafeCounterWithoutLock();
CountDownLatch latch = new CountDownLatch(N_TASKS);
Runnable runnable = () -> {
counter.increment();
latch.countDown();
};
for (int i = 0; i < N_TASKS; i++) {
EXEC.submit(runnable);
}
latch.await();
assertEquals(N_TASKS, counter.count());
EXEC.shutdown();
}