我正在研究一种(简单的)缓存解决方案,其中服务可以从缓存映射中请求缓存对象。 Cache 对象本质上也像 Map 一样工作,具有键和值以及访问和存储对象的方法。
我提出了以下解决方案,但如您所见,它包含一个转换(因为 get() 无法知道嵌套对象的类型应该是什么)。
private final Map<String, Cache<?, ?>> caches = new HashMap<String, Cache<?, ?>>();
public <K, V> Cache<K, V> getOrCreateCache(String identifier) {
if (caches.containsKey(identifier)) {
return (Cache<K, V>) caches.get(identifier);
} else {
Cache<K, V> cache = new CacheImpl<K, V>();
caches.put(identifier, cache);
return cache;
}
}
private void test() {
Cache<String, String> strCache = getOrCreateCache("string cache");
strCache.set("key", "value");
}
现在,我的问题:
- 只要正确处理类转换异常,这是一种“安全”的方法吗? (可能会捕获那些并将它们打包到自定义异常类中)
- 是否有“安全”的替代方案?一个使用泛型,如果可能的话,因为我喜欢它们而不喜欢转换。
- (没有直接关系)这是线程安全的吗?我假设不是,但是,我不是线程专家。仅使整个方法同步就足够了吗,或者(有六个客户端)会导致过多的开销/锁定吗?对此有一个巧妙的解决方案吗?
编辑:哇,很多答案,谢谢!在这里编辑以描述我在实际测试时发现的一个奇怪之处:</p>
Cache<String, String> someCache = service.getOrCreateCache(cacheIdentifier);
someCache.set("asdf", "sdfa");
Cache<String, Integer> someCacheRetrievedAgain = service.getOrCreateCache(cacheIdentifier);
System.out.println(someCacheRetrievedAgain.get("asdf")); // prints "sdfa". No errors whatsoever. Odd.
最佳答案
您可以创建一个复合键,它包含您当前的标识符和两个类实例(一个用于键,一个用于值)
public <K, V> Cache<K, V> getOrCreateCache(String identifier, Class<K> keyClass, Class<V> valueClass) {
Identifier cacheIdentifier = new Identifier(identifier, keyClass, valueClass);
// safe cast as we know that this cacheIdentifier must has a Cache<K, V>
Cache<K, V> cache = (Cache<K, V>) caches.get(identifier);
if (cache == null) {
cache = new CacheImpl<K, V>();
caches.put(cacheIdentifier, cache);
}
return cache;
}
/*
* not the most efficient implementation, but correctly implements hashCode and equals
* which is all we need
*/
private static class CacheIdentifier extends ArrayList<Object> {
private CacheIdentifier(String identifier, Class<K> keyClass, Class<V> valueClass) {
super(3);
// TODO check for null
add(identifier);
add(keyClass);
add(valueClass);
}
}
为了使这个线程安全,使用 ConcurrentHashMap而不是连同 putIfAbsent(..)
关于Java generics - Map of (typed) maps,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4733273/