面试题答案
一键面试实现思路
- 使用
Arc
来实现数据的跨线程共享,Arc
是一个原子引用计数智能指针,允许多个线程持有数据的引用。 - 使用
Mutex
来保护共享数据,确保同一时间只有一个线程可以访问和修改数据,以此保证线程安全。 - 在读取数据时,获取
Mutex
的只读锁(lock
方法返回的MutexGuard
实现了Deref
,可当作只读引用),多个线程可以同时持有只读锁进行读取操作,提高并发读性能。 - 在修改数据时,获取
Mutex
的写锁(同样是MutexGuard
,但此时可当作可变引用),由于Mutex
的特性,同一时间只有一个线程能获取写锁,保证数据修改的线程安全。
示例代码
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
// 创建一个Arc<Mutex<T>>类型的共享数据
let shared_data = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let data = Arc::clone(&shared_data);
let handle = thread::spawn(move || {
// 获取写锁来修改数据
let mut num = data.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
// 获取读锁来读取数据
let result = shared_data.lock().unwrap();
println!("Final result: {}", *result);
}
引用和可变性设置对性能和安全性的影响
- 只读引用(读锁):
- 性能:多个线程可以同时获取
Mutex
的读锁,进行并发读取操作,提高了读性能。因为只读操作不会改变数据,所以不会产生数据竞争问题。 - 安全性:由于读锁的互斥机制,同一时间内所有线程读取到的数据是一致的,保证了数据的一致性和安全性。
- 性能:多个线程可以同时获取
- 可变引用(写锁):
- 性能:每次只有一个线程可以获取
Mutex
的写锁,进行数据修改操作。这会导致在写操作时,其他线程需要等待写锁释放,降低了并发写的性能。 - 安全性:写锁的互斥机制确保同一时间只有一个线程可以修改数据,避免了数据竞争和不一致问题,保证了线程安全。
- 性能:每次只有一个线程可以获取
在实际应用中,应根据具体场景尽量减少写操作的频率,增加读操作的并发度,以提高整体的并发性能。同时,合理地管理锁的获取和释放,避免死锁等问题。