我们使用 HashMap 来缓存方法上注释的查找。使用 Spring 的 AnnotationUtils.findAnnotation 检索注释。不使用缓存会导致性能急剧下降。
我们的实现看起来像:
public class SomeService {
// Caches annotations on methods. The value can be null!
private static final Map<Method, MyAnnotation> ANNOTATION_CACHE = new HashMap<Method, MyAnnotation>();
private MyAnnotation findAnnotation(Method m) {
if (ANNOTATION_CACHE.containsKey(m)) {
return ANNOTATION_CACHE.get(m);
}
MyAnnotation a = AnnotationUtils.findAnnotation(m, MyAnnotation.class);
ANNOTATION_CACHE.put(m, a);
return a;
}
public void doSomethingWith(Class<?> clazz) {
for (Method m : clazz.getMethods()) {
MyAnnotation a = findAnnotation(m);
if (a != null) {
// do something with annotation a
}
}
}
}
现在的问题是我是否需要同步对 ANNOTATION_CACHE 映射的访问。可能发生的最糟糕的事情是两个线程并行地将相同的 (m, a) 对放入缓存映射中,这不会造成伤害,不是吗?
我的第一个想法是使用 ConcurrentHashMap,但它不允许 null 值(如果方法没有注释 => null,则这里需要 null 值)。使用 Collections.synchronizedMap() 并同步对 map 的每次访问也并不理想,因为这个 doSomethingWith() 方法被非常频繁地调用。
那么这种情况下真的有必要同步对HashMap的访问吗?缓存在运行时永远不会改变,键/值对只会插入一次,永远不会被删除,但会被读取多次。
有什么想法吗?
最佳答案
如果您有一个单独写入映射的阶段,然后有一个单独读取映射的不同阶段,那么您不需要并发集合。 您还可以通过使用不可变的映射写入后阶段包装映射来确保映射保持不变。
例如使用Guava的Immutable map :
ImmutableMap.copyOf(map);
如果您预见对集合的并发读/写/删除访问,那么您绝对应该使用 ConcurrentHashMap;因为读/写/删除操作不是原子操作,所以您最终可能会得到一些非常奇怪的结果。
My first thought was to use the ConcurrentHashMap, but it does not allow null values (which is needed here if a method has no annotation => null)
那么首先就不要插入空值;更好的是,从 map 中删除现有的 key 。
关于java - 缓存标注信息的 map 是否需要同步?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15502826/