读写锁问题
读的时候共享、写的时候独占。
方案一: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:除非并发量极低