面试题答案
一键面试设计思路
- 定义缓存接口:创建一个基础的缓存接口,定义基本的缓存操作,如获取和设置缓存数据。
- 实现具体缓存类:实现上述缓存接口,这是被装饰的核心对象,例如简单的基于内存的缓存实现。
- 定义装饰器抽象类:该类实现缓存接口,并持有一个缓存接口实例的引用,通过构造函数接收具体缓存实例。这样在装饰器类中就可以调用具体缓存类的方法,同时扩展其功能。
- 实现版本控制装饰器:继承装饰器抽象类,在获取和设置数据的方法中添加版本控制逻辑。例如,每次设置数据时更新版本号,获取数据时可以通过版本号判断数据是否是最新的。
- 线程安全机制:使用Java的
ConcurrentHashMap
来存储缓存数据,保证在高并发下的线程安全。对于版本控制,可以使用AtomicLong
来保证版本号更新的原子性。在关键操作(如设置缓存数据并更新版本号)时,使用synchronized
关键字或者ReentrantLock
来保证线程安全。
核心代码结构
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
// 缓存接口
interface Cache<K, V> {
V get(K key);
void put(K key, V value);
}
// 具体缓存实现类
class MemoryCache<K, V> implements Cache<K, V> {
private final ConcurrentHashMap<K, V> cache = new ConcurrentHashMap<>();
@Override
public V get(K key) {
return cache.get(key);
}
@Override
public void put(K key, V value) {
cache.put(key, value);
}
}
// 缓存装饰器抽象类
abstract class CacheDecorator<K, V> implements Cache<K, V> {
protected final Cache<K, V> cache;
public CacheDecorator(Cache<K, V> cache) {
this.cache = cache;
}
}
// 版本控制装饰器
class VersionedCacheDecorator<K, V> extends CacheDecorator<K, V> {
private final AtomicLong version = new AtomicLong(0);
private final ConcurrentHashMap<K, Long> keyVersionMap = new ConcurrentHashMap<>();
public VersionedCacheDecorator(Cache<K, V> cache) {
super(cache);
}
@Override
public V get(K key) {
Long storedVersion = keyVersionMap.get(key);
if (storedVersion == null || storedVersion.longValue() != version.get()) {
return null;
}
return cache.get(key);
}
@Override
public void put(K key, V value) {
synchronized (this) {
long newVersion = version.incrementAndGet();
cache.put(key, value);
keyVersionMap.put(key, newVersion);
}
}
}
在上述代码中,MemoryCache
是具体的缓存实现,CacheDecorator
是装饰器抽象类,VersionedCacheDecorator
实现了版本控制的装饰器功能。ConcurrentHashMap
保证了缓存数据存储的线程安全,AtomicLong
保证版本号更新的原子性,synchronized
关键字保证了设置数据和更新版本号操作的线程安全。