我們使用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,這裏是需要的)。使用Collections.synchronizedMap()並同步每個對地圖的訪問也並不理想,因爲doSomethingWith()方法被非常頻繁地調用。
那麼在這種情況下,是否真的有必要同步訪問HashMap?緩存nevery在運行時更改,鍵/值對只能插入一次,永遠不會被刪除,但會被多次讀取。
有什麼想法?
除了同步(並請在那裏採取@noamt的建議),您可以通過存儲「列表」來解決「無空」限制。如果你最終需要'doSomething()'處理多種註解類型,這也將簡化你的生活。 –
parsifal
2013-03-19 15:22:10
我也有這樣的假設:「可能發生的最糟糕的事情是兩個線程並行地將相同的(m,a)對放入緩存映射中,這不會造成傷害,不是嗎?」 - 這是錯誤的。細節在這個優秀的博客文章http://mailinator.blogspot.no/2009/06/beautiful-race-condition.html – hennings 2014-07-03 10:06:16