面试题答案
一键面试可能出现的问题
- 内存一致性问题:
- 不同线程对共享资源的修改可能不会及时被其他线程看到。例如,线程A修改了共享资源的值,由于缓存一致性等问题,线程B可能在一段时间内仍然看到旧值,导致数据不一致。
- 线程安全问题:
- 竞态条件:多个线程同时访问和修改共享资源时,最终结果可能取决于线程执行的顺序。比如两个线程同时对共享的计数器加1操作,如果没有适当的同步机制,可能最终计数器只增加了1而不是2。
线程安全实现代码示例(以C++为例,使用互斥锁)
#include <iostream>
#include <mutex>
#include <memory>
// 模拟共享资源类
class SharedResource {
public:
int data;
SharedResource() : data(0) {}
};
std::mutex sharedResourceMutex;
std::unique_ptr<SharedResource> sharedResourcePtr = std::make_unique<SharedResource>();
// 获取共享资源引用的线程安全函数
SharedResource& getSharedResourceRef() {
static std::mutex mtx;
std::lock_guard<std::mutex> lock(mtx);
return *sharedResourcePtr;
}
int main() {
// 模拟多线程访问
// 这里仅简单展示获取共享资源引用,实际应用中多线程会并发操作共享资源
SharedResource& res1 = getSharedResourceRef();
SharedResource& res2 = getSharedResourceRef();
return 0;
}
代码说明
- 互斥锁的使用:在
getSharedResourceRef
函数中,使用std::mutex
和std::lock_guard
来确保同一时间只有一个线程能够访问和返回共享资源的引用。std::lock_guard
在构造时自动锁定互斥锁,在析构时自动解锁,从而保证了线程安全。 - 共享资源的管理:这里使用
std::unique_ptr
来管理共享资源SharedResource
,确保资源的正确生命周期管理。实际应用中,共享资源可能是更复杂的单例对象或全局变量等。
如果使用Java,示例如下:
class SharedResource {
private int data;
public SharedResource() {
data = 0;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
}
public class ThreadSafeExample {
private static SharedResource sharedResource = new SharedResource();
private static final Object lock = new Object();
public static SharedResource getSharedResourceRef() {
synchronized(lock) {
return sharedResource;
}
}
public static void main(String[] args) {
// 模拟多线程访问
SharedResource res1 = getSharedResourceRef();
SharedResource res2 = getSharedResourceRef();
}
}
Java代码说明
- 同步块:在
getSharedResourceRef
方法中,使用synchronized
关键字创建同步块,以确保同一时间只有一个线程能获取共享资源的引用,从而保证线程安全。 - 共享资源管理:
sharedResource
是一个静态成员变量表示共享资源,lock
是一个用于同步的对象。