Commons Collections LRUMap (基本的には LinkedHashMap に小さな変更を加えたもの) を使用して、ユーザーの写真用の LRU キャッシュを実装しています。findPhoto メソッドは、数秒以内に数百回呼び出すことができます。
public class CacheHandler {
private static final int MAX_ENTRIES = 1000;
private static Map<Long, Photo> photoCache = Collections.synchronizedMap(new LRUMap(MAX_ENTRIES));
public static Map<Long, Photo> getPhotoCache() {
return photoCache;
}
}
使用法:
public Photo findPhoto(Long userId){
User user = userDAO.find(userId);
if (user != null) {
Map<Long, Photo> cache = CacheHandler.getPhotoCache();
Photo photo = cache.get(userId);
if(photo == null){
if (user.isFromAD()) {
try {
photo = LDAPService.getInstance().getPhoto(user.getLogin());
} catch (LDAPSearchException e) {
throw new EJBException(e);
}
} else {
log.debug("Fetching photo from DB for external user: " + user.getLogin());
UserFile file = userDAO.findUserFile(user.getPhotoId());
if (file != null) {
photo = new Photo(file.getFilename(), "image/png", file.getFileData());
}
}
cache.put(userId, photo);
}else{
log.debug("Fetching photo from cache, user: " + user.getLogin());
}
return photo;
}else{
return null;
}
}
ご覧のとおり、同期ブロックは使用していません。ここでの最悪のシナリオは、2 つのスレッドが同じ userId に対して cache.put(userId, photo) を実行する原因となる競合状態であると想定しています。ただし、データは 2 つのスレッドで同じであるため、問題にはなりません。
ここでの私の推論は正しいですか?そうでない場合、パフォーマンスに大きな影響を与えずに同期ブロックを使用する方法はありますか? 一度に 1 つのスレッドだけがマップにアクセスするのはやり過ぎのように感じます。