メソッドのアノテーションのルックアップをキャッシュするために 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 マップへのアクセスを同期する必要があるかどうかです。起こりうる最悪の事態は、並列の 2 つのスレッドが同じ (m, a) ペアをキャッシュ マップに入れることです。
私が最初に考えたのは、ConcurrentHashMap を使用することでしたが、null 値は許可されません (メソッドに注釈がない => null の場合に必要です)。Collections.synchronizedMap() を使用してマップへのすべてのアクセスを同期することも理想的ではありません。これは、この doSomethingWith() メソッドが非常に頻繁に呼び出されるためです。
この場合、HashMap へのアクセスを同期することが本当に必要なのでしょうか? キャッシュは実行時に変更されることはなく、キーと値のペアは一度だけ挿入され、削除されることはありませんが、何度も読み取られます。
何かご意見は?