面试题答案
一键面试缓存系统线程安全架构设计
- 读写锁(ReadWriteLock):
- 作用:用于控制对缓存数据的读写访问。读操作可以并发执行,因为读操作不会修改数据,不会产生数据不一致问题。而写操作需要独占访问,以保证数据一致性。在Java中,可以使用
ReentrantReadWriteLock
来实现读写锁。 - 示例代码:
- 作用:用于控制对缓存数据的读写访问。读操作可以并发执行,因为读操作不会修改数据,不会产生数据不一致问题。而写操作需要独占访问,以保证数据一致性。在Java中,可以使用
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
private final Lock readLock = lock.readLock();
private final Lock writeLock = lock.writeLock();
public Object readFromCache(String key) {
readLock.lock();
try {
// 从缓存读取数据逻辑
return cache.get(key);
} finally {
readLock.unlock();
}
}
public void writeToCache(String key, Object value) {
writeLock.lock();
try {
// 写入缓存数据逻辑
cache.put(key, value);
} finally {
writeLock.unlock();
}
}
- CountDownLatch:
- 作用:用于在系统初始化时,等待所有数据加载完成才能开始服务。它可以设置一个初始计数值,当每个数据加载线程完成任务时,计数值减一,当计数值为0时,主线程(或等待的线程)可以继续执行。
- 示例代码:
private CountDownLatch latch;
public CacheSystem(int dataCount) {
latch = new CountDownLatch(dataCount);
// 启动数据加载线程
for (int i = 0; i < dataCount; i++) {
new Thread(() -> {
// 数据加载逻辑
loadData();
latch.countDown();
}).start();
}
}
public void startService() {
try {
latch.await();
// 开始提供缓存服务逻辑
System.out.println("所有数据加载完成,开始提供服务");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
- Semaphore:
- 作用:在本缓存系统场景中,如果对缓存的并发访问量需要限制,例如防止过多的读操作同时进行导致系统资源耗尽,可以使用Semaphore。它可以控制同时访问的线程数量。
- 示例代码:
private final Semaphore semaphore = new Semaphore(10); // 允许最多10个线程同时访问
public Object readFromCache(String key) {
try {
semaphore.acquire();
readLock.lock();
try {
// 从缓存读取数据逻辑
return cache.get(key);
} finally {
readLock.unlock();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
}
return null;
}
通过综合运用读写锁保证读写操作的线程安全与数据一致性,CountDownLatch确保系统初始化完成后再提供服务,以及Semaphore(根据实际需求)控制并发访问量,从而设计出一个线程安全的缓存系统架构。