J'implémente un cache LRU pour les photos des utilisateurs, en utilisant Commons Collections LRUMap (qui est fondamentalement un LinkedHashMap avec de petites modifications). La méthode findPhoto peut être appelée plusieurs centaines de fois en quelques secondes.L'utilisation d'une carte de cache est-elle sûre dans un environnement multithread?
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;
}
}
Utilisation:
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;
}
}
Comme vous pouvez le voir, je ne suis pas en utilisant des blocs de synchronisation. Je suppose que le cas le plus défavorable est une condition de concurrence qui entraîne l'exécution de deux threads par cache.put (userId, photo) pour le même userId. Mais les données seront les mêmes pour deux threads, donc ce n'est pas un problème.
Est-ce que mon raisonnement est correct? Si ce n'est pas le cas, existe-t-il un moyen d'utiliser un bloc de synchronisation sans avoir un impact important sur les performances? Avoir seulement 1 fil accédant à la carte à la fois se sent comme exagéré.
Merci pour l'idée, très instructif. –