如何实现含Read、Write方法的Resources类满足指定并发约束
核心实现思路
这是典型的读写锁适用场景,刚好匹配你提出的三个约束,核心逻辑如下:
- 维护一个
正在读取的线程数计数器,初始值为0 - 维护一个
写操作执行中的标志位/排他锁,保证同一时间最多只有一个写线程执行 Read()方法执行逻辑:- 先判断当前是否有写操作正在执行,如果有则阻塞等待,直到写操作结束
- 进入读操作前,原子性将读线程计数器+1
- 执行读业务逻辑
- 读操作结束后,原子性将读线程计数器-1,如果减完后计数器归0,通知等待的写线程可以执行
Write()方法执行逻辑:- 先获取排他锁,阻塞其他写线程进入
- 等待所有正在执行的读线程全部结束,即读线程计数器归0
- 执行写业务逻辑
- 释放排他锁,通知等待的读/写线程可以执行
工业级实现优先用语言内置的读写锁工具类即可,不需要手动手写,避免出现锁顺序错误、信号量遗漏等并发问题:Java可使用ReentrantReadWriteLock、C#可使用ReaderWriterLockSlim、Go可使用sync.RWMutex。
代码示例(C#版本)
内置类实现(推荐)
public class Resources { // .NET内置的读写锁实现,性能和安全性都优于手写实现 private readonly ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim(); public void Read() { // 进入读锁,允许多个线程同时获取 _rwLock.EnterReadLock(); try { // 此处编写读业务逻辑 } finally { // 必须在finally块释放锁,避免异常导致锁泄漏 _rwLock.ExitReadLock(); } } public void Write() { // 进入写锁,同一时间仅一个线程能获取,且会阻塞所有读锁获取请求 _rwLock.EnterWriteLock(); try { // 此处编写写业务逻辑 } finally { _rwLock.ExitWriteLock(); } } }
手写实现(学习用)
public class Resources { private readonly object _lock = new object(); private int _readCount = 0; private bool _isWriting = false; public void Read() { lock (_lock) { // 有写操作正在执行则等待 while (_isWriting) { Monitor.Wait(_lock); } _readCount++; } try { // 此处编写读业务逻辑 } finally { lock (_lock) { _readCount--; if (_readCount == 0) { // 读线程全部退出,通知等待的写线程 Monitor.PulseAll(_lock); } } } } public void Write() { lock (_lock) { // 有写操作在执行、或者有读线程在读则等待 while (_isWriting || _readCount > 0) { Monitor.Wait(_lock); } _isWriting = true; } try { // 此处编写写业务逻辑 } finally { lock (_lock) { _isWriting = false; // 通知所有等待的读/写线程 Monitor.PulseAll(_lock); } } } }
注意事项
- 上面的手写实现是读优先模式,也就是如果一直有读线程进入,写线程可能会出现饥饿,如果需要公平调度,可以额外增加等待写线程的计数,读线程发现有等待的写线程时主动让路即可。
- 所有锁的释放必须放在
finally块中,避免业务逻辑抛出异常时锁未释放,导致死锁。
内容的提问来源于stack exchange,提问作者rshubh
相关产品推荐
相关产品推荐

