多个读取者同时访问数据,写入者独占访问
- 读-读共享:当没有写入者时,任意数量的线程可以同时持有读锁。这意味着读取操作可以并行执行,无需排队。
- 写-写互斥:同一时刻只能有一个线程持有写锁。
- 读-写互斥:只要有写入者持有写锁,所有读取者必须等待;反之,只要有读取者持有读锁,写入者也必须等待所有读取者释放锁后才能获取写锁。
use std::sync::{Arc, RwLock};
use std::thread;
fn main() {
let mut handles = Vec::new(); // 存储线程任务的句柄
let data = Arc::new(RwLock::new(vec![1, 2, 3]));
for i in 0..10 {
let datar = data.clone();
handles.push(thread::spawn(move || {
let d = datar.read().unwrap();
println!("{}线程读到的数据:{:?}", i, d);
}));
}
let dataw = data.clone();
handles.push(thread::spawn(move || {
let mut d = dataw.write().unwrap();
d.push(4);
println!("写入后的数据:{:?}", d);
}));
for handle in handles {
handle.join().unwrap(); // 等待所有线程完成执行
}
println!("最后的数据:{:?}", data.read().unwrap());
}
10.1 RwLock 与 Mutex 对比
- Mutex 的局限:
Mutex是纯粹的互斥锁。即使多个线程只是想要读取数据,它们也必须排队,一次只有一个线程能进入临界区。这在读取频繁、写入稀少的场景下会造成不必要的串行化,降低性能。 - RwLock 的优势:它细化了锁的粒度。在“读多写少”的场景中,大部分时间多个线程可以并行读取,只有在少数写入发生时才进行互斥同步。这大大减少了线程阻塞的时间,提高了系统的整体吞吐量。
| 特性 | Mutex<T> | RwLock<T> |
|---|---|---|
| 并发读取 | ❌ 不支持(串行) | ✅ 支持(并行) |
| 并发写入 | ❌ 不支持(串行) | ❌ 不支持(串行) |
| 实现复杂度 | 低 | 高 |
| 适用场景 | 通用、写频繁、短临界区 | 读多写少、长读取操作 |
| 主要风险 | 性能瓶颈(读排队) | 写饥饿、锁升级死锁 |
最佳实践建议:
默认首选 Mutex<T>,因为它简单且安全。只有当你明确观察到读取操作成为性能瓶颈,且场景符合“读多写少”时,才考虑切换到 RwLock<T>。在使用 RwLock 时,务必注意避免锁升级,并监控是否存在写饥饿现象。
RwLock<T>(读写锁)&spm=1001.2101.3001.5002&articleId=162481931&d=1&t=3&u=544816bb5af044d290d82696c3ff00cb)
724

被折叠的 条评论
为什么被折叠?



