Mutex
(互斥锁):
Mutex
提供了一种机制来保证在同一时间只有一个线程可以访问被其保护的数据。当一个线程想要访问 Mutex
保护的数据时,它必须先获取锁。如果锁已经被其他线程持有,那么当前线程会被阻塞,直到锁被释放。通过这种方式,避免了多个线程同时修改数据导致的数据竞争问题,从而确保线程安全。例如:
use std::sync::{Mutex, Arc};
use std::thread;
let data = Arc::new(Mutex::new(0));
let data_clone = data.clone();
let handle = thread::spawn(move || {
let mut num = data_clone.lock().unwrap();
*num += 1;
});
let mut num = data.lock().unwrap();
*num += 1;
handle.join().unwrap();
RwLock
(读写锁):
RwLock
区分了读操作和写操作。多个线程可以同时获取读锁来读取数据,因为读操作不会修改数据,所以不会产生数据竞争。但是,当有线程想要获取写锁时,必须等待所有读锁都被释放,并且在写锁被持有时,其他线程既不能获取读锁也不能获取写锁。这保证了写操作的原子性和独占性,同时在读多写少的场景下提高了并发性能,确保线程安全。例如:
use std::sync::{RwLock, Arc};
use std::thread;
let data = Arc::new(RwLock::new(0));
let data_clone = data.clone();
let handle = thread::spawn(move || {
let mut num = data_clone.write().unwrap();
*num += 1;
});
let num = data.read().unwrap();
handle.join().unwrap();
Arc
(原子引用计数)和 Weak
(弱引用):
Arc
用于在多个线程间共享数据,它通过原子引用计数机制来记录有多少个 Arc
实例指向同一数据。只有当引用计数为 0 时,数据才会被释放,这确保了在多线程环境下数据不会被提前释放导致悬垂指针等问题。Weak
是 Arc
的弱引用,它不会增加引用计数,主要用于解决 Arc
可能产生的循环引用问题,进一步确保线程安全。例如:
use std::sync::Arc;
let strong = Arc::new(1);
let weak = Arc::downgrade(&strong);
drop(strong);
if let Some(strong_again) = weak.upgrade() {
println!("We got the strong reference back: {}", strong_again);
} else {
println!("The strong reference was dropped.");
}