353 lines
9.1 KiB
Markdown
353 lines
9.1 KiB
Markdown
|
||
无锁编程(Lock-Free Programming)是一种通过原子操作(如CAS)而非传统锁机制实现线程安全的技术,`volatile`保证可见性,CAS保证原子性,二者结合构成经典的无锁编程模式。
|
||
|
||
## **一、核心组件原理**
|
||
|
||
### **1. volatile 的作用**
|
||
```java
|
||
// volatile 保证可见性和有序性
|
||
private volatile int value;
|
||
|
||
// 主要特性:
|
||
// 1. 可见性:写操作立即刷新到主内存
|
||
// 2. 有序性:禁止指令重排序
|
||
// 3. 不保证原子性(需要CAS补充)
|
||
```
|
||
|
||
### **2. CAS (Compare-And-Swap)**
|
||
```java
|
||
// 伪代码表示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. 无锁计数器**
|
||
```java
|
||
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的实现**
|
||
```java
|
||
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. 无锁栈**
|
||
```java
|
||
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队列)**
|
||
```java
|
||
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. 适用场景**
|
||
```java
|
||
// 1. 高并发计数器
|
||
// 2. 状态标志位
|
||
// 3. 累积统计信息
|
||
// 4. 实现无锁数据结构
|
||
// 5. 线程池的工作窃取
|
||
```
|
||
|
||
### **2. 最佳实践**
|
||
```java
|
||
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. 性能优化技巧**
|
||
```java
|
||
// 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问题**
|
||
```java
|
||
// 解决方案:使用版本戳或标记指针
|
||
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**
|
||
```java
|
||
// 解决方案:限制自旋次数或使用退避策略
|
||
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. 内存顺序问题**
|
||
```java
|
||
// 使用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);
|
||
}
|
||
}
|
||
```
|
||
|
||
## **六、性能对比示例**
|
||
|
||
```java
|
||
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无锁编程模式的核心优势:**
|
||
1. **高性能**:避免线程阻塞和上下文切换
|
||
2. **可伸缩性**:竞争不会导致性能急剧下降
|
||
3. **避免死锁**:没有锁的获取顺序问题
|
||
|
||
**使用建议:**
|
||
- 简单操作用`AtomicXxx`类
|
||
- 复杂数据结构用`AtomicReference` + 循环CAS
|
||
- 高并发写场景考虑`LongAdder`、`ConcurrentLinkedQueue`等
|
||
- 始终监控CAS失败率,过高说明竞争激烈
|
||
- Java 9+优先使用`VarHandle`替代`Unsafe`
|
||
|
||
这种模式是现代高并发框架(如Disruptor、Netty、Akka)的基石,理解它对于编写高性能并发程序至关重要。 |