面试题答案
一键面试可能遇到的并发问题
- 重复初始化:在多线程环境下,多个线程可能同时尝试初始化连接池,导致连接池被重复初始化,浪费资源并可能造成数据不一致。
解决方案
使用 OnceCell
来确保连接池只被初始化一次。OnceCell
提供了 get_or_init
方法,该方法能在并发环境下安全地初始化值,保证只有一个线程会执行初始化逻辑,其他线程等待初始化完成并获取已初始化的值。
关键代码示例(以 Rust 语言为例)
use std::sync::{Arc, OnceCell};
use std::net::TcpListener;
use std::thread;
// 定义全局连接池
static CONNECTION_POOL: OnceCell<Arc<TcpListener>> = OnceCell::new();
fn get_connection_pool() -> Arc<TcpListener> {
CONNECTION_POOL.get_or_init(|| {
let listener = TcpListener::bind("127.0.0.1:8080").expect("Failed to bind");
Arc::new(listener)
})
}
fn main() {
// 模拟多个线程
let mut handles = vec![];
for _ in 0..10 {
let handle = thread::spawn(|| {
let pool = get_connection_pool();
println!("Thread got connection pool: {:?}", pool);
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
}
在上述代码中:
- 定义了一个
OnceCell
类型的静态变量CONNECTION_POOL
来存储连接池。 get_connection_pool
函数通过get_or_init
方法来获取或初始化连接池。初始化逻辑中创建了一个TcpListener
并包装成Arc
类型。- 在
main
函数中模拟了多个线程,每个线程调用get_connection_pool
函数获取连接池,确保连接池只被初始化一次。