CAS(比较并交换,Compare And Swap)是一种多线程并发编程中的原子操作。它是一种乐观锁技术,用于解决 多线程环境下的数据竞争问题。CAS操作通过比较内存中的值与预期值是否相等来确定是否进行交换,如果相等,则进行交换,否则重新尝试。
Java中的CAS操作通常使用Atomic类来实现,例如AtomicInteger、AtomicLong等。这些类提供了方法来进行原子操作,如getAndSet、compareAndSet等。
以下是CAS操作的基本流程:
-
读取内存中的值:线程从内存中读取要操作的数据的当前值。
-
比较预期值:线程将读取的值与预期值进行比较。
-
判断是否相等:如果读取到的值与预期值相等,则继续执行,否则重新尝试。
-
进行交换操作:如果相等,则进行交换操作,将新值写回内存。
CAS操作的优点是它是一种无锁技术,避免了传统的锁机制带来的线程阻塞和上下文切换开销。只有一个线程能够成功执行CAS操作,其他线程需要重新尝试。
以下是一个简单的Java中CAS操作的示例:
import java.util.concurrent.atomic.AtomicInteger;
public class CASExample {
private static AtomicInteger counter = new AtomicInteger(0);
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
int oldValue = counter.get();
while (!counter.compareAndSet(oldValue, oldValue + 1)) {
oldValue = counter.get();
}
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
int oldValue = counter.get();
while (!counter.compareAndSet(oldValue, oldValue + 1)) {
oldValue = counter.get();
}
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Counter: " + counter.get());
}
}
在这个示例中,两个线程分别对计数器进行递增操作,使用CAS操作进行原子性的增加。最终输出的计数器值应该是2000。
需要注意的是,虽然CAS操作避免了锁的竞争,但它并不能解决所有的并发问题。CAS操作仍然存在ABA问题(即值在多次修改中经历了A->B->A的变化)和自旋等待的问题。因此,在实际应用中,需要根据具体情况来选择合适的并发控制方案。
!!!线程同时执行CAS操作时,不会发生竞争条件。
CAS的应用场景:
CAS主要用于无锁算法和数据结构,以下是一些常见的应用场景:
- 原子变量类:如
AtomicInteger
、AtomicLong
、AtomicReference
等。 - 并发集合类:如
ConcurrentLinkedQueue
、ConcurrentHashMap
等。 - 线程池中的任务计数:如
ForkJoinPool
。 - 实现自旋锁:通过自旋尝试不断进行CAS操作直到成功。