![](/img/trans.png)
[英]Does map need to be synchronized if for each entry only one thread is accessing it?
[英]Does a map that caches annotation info need to be synchronized?
我们正在使用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,则在此需要)。 使用Collections.synchronizedMap()并使每个对地图的访问同步也是不理想的,因为经常调用此doSomethingWith()方法。
因此,在这种情况下,是否真的需要同步对HashMap的访问? 缓存在运行时的永不更改,并且键/值对仅插入一次就不会删除,但会被读取很多次。
有什么想法吗?
如果您有一个阶段专门用于映射,而另一个阶段则专门从中读取映射,那么您就不需要并发集合。 您还可以通过使用不变的地图写入后阶段包装地图来确保地图保持不变。
例如,使用番石榴的不可变地图 :
ImmutableMap.copyOf(map);
如果您预见到对集合的并发读/写/删除访问,那么您绝对应该使用ConcurrentHashMap; 由于读/写/删除操作不是原子操作,因此您可能会得到一些非常奇怪的结果。
我的第一个想法是使用ConcurrentHashMap,但是它不允许使用null值(如果方法没有注释=> null,则在此需要此值)
然后,不要首先插入null值 ; 更好的是,从地图上删除现有密钥。
现在的问题是,是否需要同步对ANNOTATION_CACHE映射的访问。 可能发生的最糟糕的情况是,两个并行线程将相同的(m,a)对放入缓存映射中,这不会造成伤害,不是吗?
是的,如果第一个看跌期权需要扩展支持哈希图的数组,可能会造成伤害
如果在第一个put扩展哈希图的同时调用第二个put,则可能会发生不良且不可预测的结果。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.