读写锁问题

读的时候共享、写的时候独占。

方案一:ReentrantReadWriteLock(推荐方案)

核心特性:

读锁共享:允许多线程并发读取
写锁独占:写操作时完全互斥135
锁降级:写线程可降级为读锁,保证数据一致性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import java.util.concurrent.locks.*;
public class ReadWriteResource {
private int value;
private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
private final Lock readLock = rwLock.readLock();
private final Lock writeLock = rwLock.writeLock();
// 读操作(共享)
public int readValue() {
readLock.lock();
try {
return value;
} finally {
readLock.unlock();
}
}
// 写操作(独占)
public void writeValue(int newValue) {
writeLock.lock();
try {
value = newValue;
} finally {
writeLock.unlock();
}
}
}

优势:

明确的读写分离,符合业务语义35
支持公平/非公平锁策略19
读操作完全无阻塞,适合读多写少场景15

方案二:StampedLock(高性能方案)

核心特性:

乐观读:无锁读取,通过版本号校验数据一致性28
悲观读:类似ReentrantReadWriteLock的读锁8
写锁独占:与所有读操作互斥

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import java.util.concurrent.locks.*;
public class StampedResource {
private int value;
private final StampedLock stampedLock = new StampedLock();
// 乐观读(无锁)
public int optimisticRead() {
long stamp = stampedLock.tryOptimisticRead();
int currentValue = value;
if (!stampedLock.validate(stamp)) { // 检查写冲突<sup>8</sup>
stamp = stampedLock.readLock(); // 降级为悲观读
try {
currentValue = value;
} finally {
stampedLock.unlockRead(stamp);
}
}
return currentValue;
}
// 写操作(独占)
public void writeValue(int newValue) {
long stamp = stampedLock.writeLock();
try {
value = newValue;
} finally {
stampedLock.unlockWrite(stamp);
}
}
}

优势:

乐观读性能比传统读锁高30%+(读多写少场景)8
支持锁升级(读锁→写锁)8
避免写线程饥饿问题8

推荐选择:

优先使用ReentrantReadWriteLock:常规读写分离需求35
选择StampedLock:读操作占比超过90%的高并发场景8
避免使用synchronized:除非并发量极低