我正在研究一种(简单的)缓存解决方案,其中服务可以从缓存地图请求缓存对象. 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");
}
现在,我的问题:
>只要正确处理classcastexceptions,这是一种“安全”的方法吗? (可能会捕获它们并将它们打包成自定义异常类)
>有“安全”选择吗?一个人用泛型,如果可能的话,因为我喜欢他们而不喜欢演员.
>(不直接相关)这是线程安全吗?我假设没有,但那时,我不是线程专家.仅仅使整个方法同步,或者那个(有六个客户端)导致过多的开销/锁定是否足够?那有一个很好的解决方案吗?
编辑:哇,很多答案,谢谢!在这里编辑以描述我在实际测试时发现的奇怪现象:
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.
最佳答案 您可以创建一个复合键,其中包含您当前的标识符和两个Class实例(一个用于键,一个用于值)
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(..)