面试题答案
一键面试1. CAS基本工作原理
CAS 是一种乐观锁策略,其核心涉及三个操作数:
- 内存位置(V):要更新的内存值。
- 预期原值(A):在执行操作前,对内存位置 V 预期的值。
- 新值(B):如果内存位置 V 的实际值与预期原值 A 相匹配,就将内存位置 V 的值更新为新值 B。
CAS 操作过程如下:首先读取内存位置 V 的实际值,将其与预期原值 A 比较,如果二者相等,意味着在读取 V 之后没有其他线程修改过 V 的值,此时将 V 的值更新为新值 B;如果不相等,则说明其他线程已经修改了 V 的值,当前操作失败,通常需要重试操作,直到成功。
2. 多线程编程场景下解决的并发问题
计数器实现
在多线程环境下实现计数器时,如果使用传统的变量自增操作(如 count++
),由于其不是原子操作,多个线程同时执行会导致数据不一致问题。例如:
class Counter {
private int count = 0;
public void increment() {
count++;
}
public int getCount() {
return count;
}
}
当多个线程同时调用 increment
方法时,可能会出现计数不准确的情况。
使用 CAS 实现线程安全的计数器:
import java.util.concurrent.atomic.AtomicInteger;
class CASCounter {
private AtomicInteger count = new AtomicInteger(0);
public void increment() {
while (true) {
int current = count.get();
boolean success = count.compareAndSet(current, current + 1);
if (success) {
break;
}
}
}
public int getCount() {
return count.get();
}
}
这里 AtomicInteger
类内部使用 CAS 操作来实现原子的自增,保证了多线程环境下计数器的正确性。
锁机制
在实现锁机制方面,CAS 可以用于构建无锁数据结构。例如,使用 CAS 实现简单的自旋锁:
class SpinLock {
private AtomicBoolean locked = new AtomicBoolean(false);
public void lock() {
while (true) {
boolean expected = false;
boolean success = locked.compareAndSet(expected, true);
if (success) {
return;
}
}
}
public void unlock() {
locked.set(false);
}
}
线程在获取锁时,通过 CAS 操作尝试将 locked
从 false
设置为 true
,如果成功则获取到锁;如果失败则不断重试(自旋),直到获取到锁。解锁时只需将 locked
设置为 false
。这样通过 CAS 操作避免了传统锁机制中可能出现的死锁等问题,并且在高并发且锁竞争不激烈的场景下,性能优于传统锁。