面试题答案
一键面试设计思路
- 使用
Lazy
类型:Lazy
类型提供了延迟初始化功能,并且在多线程环境下是安全的。 - 管理共享资源: 使用
Mutex
或RwLock
来保护共享资源,确保按照严格的顺序进行访问和修改。 - 处理竞争条件: 通过锁机制避免多个线程同时初始化对象或访问共享资源。
- 数据一致性: 使用锁和适当的初始化逻辑确保在对象初始化完成前,不会有线程读取到未初始化或部分初始化的数据。
核心代码实现
use std::sync::{Arc, Mutex, RwLock, Lazy};
use std::thread;
// 共享资源
static SHARED_RESOURCE1: Lazy<Arc<RwLock<i32>>> = Lazy::new(|| Arc::new(RwLock::new(0)));
static SHARED_RESOURCE2: Lazy<Arc<Mutex<String>>> = Lazy::new(|| Arc::new(Mutex::new(String::new())));
// 复杂对象
static COMPLEX_OBJECT: Lazy<Arc<Mutex<ComplexObject>>> = Lazy::new(|| {
// 确保按照顺序获取资源
let resource1 = Arc::clone(&SHARED_RESOURCE1);
let resource2 = Arc::clone(&SHARED_RESOURCE2);
let value1 = resource1.read().unwrap();
let value2 = resource2.lock().unwrap();
ComplexObject {
data1: *value1,
data2: value2.clone()
}.into()
});
struct ComplexObject {
data1: i32,
data2: String,
}
fn main() {
let handle1 = thread::spawn(|| {
let object = COMPLEX_OBJECT.lock().unwrap();
println!("Thread 1 accessed object: data1 = {}, data2 = {}", object.data1, object.data2);
});
let handle2 = thread::spawn(|| {
let object = COMPLEX_OBJECT.lock().unwrap();
println!("Thread 2 accessed object: data1 = {}, data2 = {}", object.data1, object.data2);
});
handle1.join().unwrap();
handle2.join().unwrap();
}
代码说明
- 共享资源定义: 使用
Lazy
定义了两个共享资源SHARED_RESOURCE1
和SHARED_RESOURCE2
,分别使用RwLock
和Mutex
进行保护。 - 复杂对象定义:
COMPLEX_OBJECT
也是通过Lazy
进行延迟初始化,在初始化时按照顺序获取共享资源。 - 多线程访问: 在
main
函数中创建两个线程来访问COMPLEX_OBJECT
,展示多线程环境下的使用。
通过这种方式,我们可以在多线程环境下安全地实现延迟初始化,并处理好竞争条件和数据一致性问题。