9.1 KiB
9.1 KiB
无锁编程(Lock-Free Programming)是一种通过原子操作(如CAS)而非传统锁机制实现线程安全的技术,volatile保证可见性,CAS保证原子性,二者结合构成经典的无锁编程模式。
一、核心组件原理
1. volatile 的作用
// volatile 保证可见性和有序性
private volatile int value;
// 主要特性:
// 1. 可见性:写操作立即刷新到主内存
// 2. 有序性:禁止指令重排序
// 3. 不保证原子性(需要CAS补充)
2. CAS (Compare-And-Swap)
// 伪代码表示CAS操作
boolean compareAndSwap(int expectedValue, int newValue) {
if (this.value == expectedValue) {
this.value = newValue;
return true;
}
return false;
}
// Java中的原子类底层实现
// sun.misc.Unsafe 类的CAS操作
public final native boolean compareAndSwapInt(
Object o, long offset, int expected, int x);
二、典型实现模式
1. 无锁计数器
public class LockFreeCounter {
private volatile int value;
public void increment() {
int oldValue;
do {
oldValue = value; // volatile读,获取最新值
} while (!compareAndSet(oldValue, oldValue + 1));
}
// 模拟CAS操作(实际使用AtomicInteger或Unsafe)
private synchronized boolean compareAndSet(int expected, int newValue) {
if (value == expected) {
value = newValue;
return true;
}
return false;
}
}
2. 使用AtomicInteger的实现
import java.util.concurrent.atomic.AtomicInteger;
public class AtomicCounter {
private AtomicInteger count = new AtomicInteger(0);
public void increment() {
int oldValue;
do {
oldValue = count.get();
} while (!count.compareAndSet(oldValue, oldValue + 1));
}
// 简化写法
public void incrementSimple() {
count.getAndIncrement(); // 内部也是CAS实现
}
}
三、复杂数据结构示例
1. 无锁栈
import java.util.concurrent.atomic.AtomicReference;
public class LockFreeStack<T> {
private static class Node<T> {
T value;
Node<T> next;
Node(T value) {
this.value = value;
}
}
private AtomicReference<Node<T>> top = new AtomicReference<>();
public void push(T value) {
Node<T> newHead = new Node<>(value);
Node<T> oldHead;
do {
oldHead = top.get();
newHead.next = oldHead;
} while (!top.compareAndSet(oldHead, newHead));
}
public T pop() {
Node<T> oldHead;
Node<T> newHead;
do {
oldHead = top.get();
if (oldHead == null) {
return null;
}
newHead = oldHead.next;
} while (!top.compareAndSet(oldHead, newHead));
return oldHead.value;
}
}
2. 无锁队列(Michael-Scott队列)
import java.util.concurrent.atomic.AtomicReference;
public class LockFreeQueue<T> {
private static class Node<T> {
T value;
AtomicReference<Node<T>> next;
Node(T value) {
this.value = value;
this.next = new AtomicReference<>(null);
}
}
private AtomicReference<Node<T>> head;
private AtomicReference<Node<T>> tail;
public LockFreeQueue() {
Node<T> dummy = new Node<>(null);
head = new AtomicReference<>(dummy);
tail = new AtomicReference<>(dummy);
}
public void enqueue(T value) {
Node<T> newNode = new Node<>(value);
Node<T> currentTail;
Node<T> currentTailNext;
while (true) {
currentTail = tail.get();
currentTailNext = currentTail.next.get();
if (currentTail == tail.get()) {
if (currentTailNext == null) {
// 尝试链接新节点
if (currentTail.next.compareAndSet(null, newNode)) {
// 尝试移动tail指针
tail.compareAndSet(currentTail, newNode);
return;
}
} else {
// 帮助其他线程完成操作
tail.compareAndSet(currentTail, currentTailNext);
}
}
}
}
}
四、应用场景与最佳实践
1. 适用场景
// 1. 高并发计数器
// 2. 状态标志位
// 3. 累积统计信息
// 4. 实现无锁数据结构
// 5. 线程池的工作窃取
2. 最佳实践
public class OptimizedCASUsage {
// 1. 减少CAS失败率:使用局部变量缓存
public void optimizedIncrement(AtomicInteger counter) {
int oldValue;
int newValue;
do {
oldValue = counter.get(); // volatile读
newValue = oldValue + 1;
} while (!counter.compareAndSet(oldValue, newValue));
}
// 2. 指数退避策略减少竞争
public void incrementWithBackoff(AtomicInteger counter) {
int delay = 1;
while (true) {
int oldValue = counter.get();
if (counter.compareAndSet(oldValue, oldValue + 1)) {
break;
}
// 失败后指数退避
LockSupport.parkNanos(delay);
delay = Math.min(delay * 2, 1000000); // 最大1ms
}
}
}
3. 性能优化技巧
// 1. 使用LongAdder替代AtomicLong(高并发写场景)
import java.util.concurrent.atomic.LongAdder;
public class HighPerformanceCounter {
private LongAdder adder = new LongAdder();
public void increment() {
adder.increment(); // 内部使用分段CAS
}
public long sum() {
return adder.sum();
}
}
// 2. 使用Striped64思想减少竞争
// 3. 考虑缓存行填充避免伪共享
@sun.misc.Contended
class PaddedAtomicLong extends AtomicLong {
// 自动填充缓存行
}
五、注意事项与陷阱
1. ABA问题
// 解决方案:使用版本戳或标记指针
import java.util.concurrent.atomic.AtomicStampedReference;
public class ABASolution {
private AtomicStampedReference<Integer> ref =
new AtomicStampedReference<>(0, 0);
public void update(int newValue) {
int[] stampHolder = new int[1];
int oldValue;
int oldStamp;
do {
oldValue = ref.get(stampHolder);
oldStamp = stampHolder[0];
} while (!ref.compareAndSet(
oldValue, newValue,
oldStamp, oldStamp + 1));
}
}
2. 自旋消耗CPU
// 解决方案:限制自旋次数或使用退避策略
public class SpinLimit {
private static final int MAX_SPINS = 1000;
public boolean casWithSpinLimit(AtomicInteger atomic) {
int spins = 0;
int oldValue;
do {
if (spins++ > MAX_SPINS) {
Thread.yield(); // 让出CPU
spins = 0;
}
oldValue = atomic.get();
} while (!atomic.compareAndSet(oldValue, oldValue + 1));
return true;
}
}
3. 内存顺序问题
// 使用VarHandle提供更精细的内存顺序控制
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
public class VarHandleExample {
private int value;
private static final VarHandle VALUE_HANDLE;
static {
try {
VALUE_HANDLE = MethodHandles.lookup()
.findVarHandle(VarHandleExample.class, "value", int.class);
} catch (Exception e) {
throw new Error(e);
}
}
public void atomicUpdate() {
// 使用acquire-release语义
VALUE_HANDLE.getAndAddAcquire(this, 1);
}
}
六、性能对比示例
public class LockVsCASBenchmark {
private final Object lock = new Object();
private int lockCounter = 0;
private AtomicInteger casCounter = new AtomicInteger(0);
// 锁实现
public void incrementWithLock() {
synchronized (lock) {
lockCounter++;
}
}
// CAS实现
public void incrementWithCAS() {
casCounter.incrementAndGet();
}
// 测试结果通常:
// 低竞争:锁性能更好(锁偏向优化)
// 中等竞争:二者相当
// 高竞争:CAS性能更好(避免上下文切换)
}
总结
volatile + CAS无锁编程模式的核心优势:
- 高性能:避免线程阻塞和上下文切换
- 可伸缩性:竞争不会导致性能急剧下降
- 避免死锁:没有锁的获取顺序问题
使用建议:
- 简单操作用
AtomicXxx类 - 复杂数据结构用
AtomicReference+ 循环CAS - 高并发写场景考虑
LongAdder、ConcurrentLinkedQueue等 - 始终监控CAS失败率,过高说明竞争激烈
- Java 9+优先使用
VarHandle替代Unsafe
这种模式是现代高并发框架(如Disruptor、Netty、Akka)的基石,理解它对于编写高性能并发程序至关重要。