Comment voulez-vous mettre en œuvre un cache LRU en Java?
S'il vous plaît ne pas dire EHCache ou OSCache, etc. Supposons, pour les fins de cette question que je veux implémenter mon propre juste en utilisant le kit de développement (learning by doing). Étant donné que le cache doit être utilisé dans un environnement multithread, ce qui structures de données utilisez-vous? J'ai déjà mis en place une aide LinkedHashMap et Les Collections de#synchronizedMap, mais je suis curieux de savoir si l'une des nouvelles concurrentes des collections seraient de meilleurs candidats.
Mise à JOUR: je viens de lire à travers Yegge dernier quand j'ai découvert cette pépite:
Si vous avez besoin de constante de temps d'accès et que vous souhaitez maintenir l'ordre d'insertion, vous ne pouvez pas faire mieux qu'une LinkedHashMap, une très bonne structure de données. La seule façon dont il pourrait être plus merveilleux est que si il y avait une version simultanée. Mais hélas.
Je pensais presque exactement la même chose avant, je suis allé avec le LinkedHashMap
+ Collections#synchronizedMap
mise en œuvre je l'ai mentionné ci-dessus. Agréable de savoir que je n'avais pas juste oublié quelque chose.
Sur la base des réponses jusqu'à présent, il semble que mon meilleur pari pour une très simultanées LRU serait d'étendre ConcurrentHashMap à l'aide de certains de la même logique que LinkedHashMap
utilise.
O(1)
version requise: stackoverflow.com/questions/23772102/...- Question très semblable aussi ici
Vous devez vous connecter pour publier un commentaire.
J'aime beaucoup de ces suggestions, mais pour l'instant je pense que je vais rester avec
LinkedHashMap
+Collections.synchronizedMap
. Si je ne le revoir dans le futur, je vais probablement travailler sur l'extension deConcurrentHashMap
de la même façonLinkedHashMap
s'étendHashMap
.Mise à JOUR:
À la demande, voici l'essentiel de mon actuel de mise en œuvre.
LinkedHashMap
soutiennent explicitement cette méthode pour créer un LRU mise en œuvre.1.0f
? Le but de cette façon de faire est d'avoir exactement une allocation (le premier) et d'éviter de re-hachage du contenu actuel de laMap
lorsqu'il doit être augmenté pour tenir le nouvel élément.Ou de l'utiliser Apache Commons structure de données:
https://commons.apache.org/proper/commons-collections/apidocs/org/apache/commons/collections4/map/LRUMap.html
Collections#synchronizedMap
. Merci pour le lien, cependant. Avoir un upvote.Si je faisais ça à nouveau à partir de zéro aujourd'hui, j'aimerais utiliser la Goyave est
CacheBuilder
.LinkedHashMap
est O(1), mais requiert une synchronisation. Pas besoin de réinventer la roue il.2 options pour l'augmentation de la concurrence:
1.
Créer plusieurs
LinkedHashMap
, et de hachage en eux:exemple:
LinkedHashMap[4], index 0, 1, 2, 3
. Sur la clé nekey%4
(oubinary OR
sur[key, 3]
) de choisir la carte pour faire un put/get/supprimer.2.
Vous pourriez faire un "presque" LRU en étendant
ConcurrentHashMap
, et ayant un lien de hachage de la carte comme la structure dans chacune des régions à l'intérieur d'elle. Le verrouillage se ferait plus granulaire queLinkedHashMap
qui est synchronisé. Sur unput
ouputIfAbsent
seulement un verrou sur la tête et la queue de la liste, est nécessaire (par région). Sur un supprimer ou obtenir l'ensemble de la région doit être verrouillé. Je suis curieux de savoir si Atomique listes liées, de la sorte, peut aider à ici -- probablement à la tête de la liste. Peut-être pour plus d'.La structure ne serait pas garder le total de la commande, mais seulement de l'ordre par région. Tant que le nombre d'entrées est beaucoup plus grande que le nombre de régions, ce est assez bon pour la plupart des caches. Chaque région devra avoir sa propre entrée comte, ce serait utilisée plutôt que le compte global pour l'expulsion de déclenchement.
La valeur par défaut du nombre de régions dans un
ConcurrentHashMap
est de 16, ce qui est beaucoup pour la plupart des serveurs aujourd'hui.serait plus facile à écrire et plus rapide, en vertu de modéré la simultanéité.
serait plus difficile à écrire, mais l'échelle de mieux à une très forte concurrence. Il serait plus lent pour l'accès normal (tout comme
ConcurrentHashMap
est plus lent queHashMap
où il n'y a pas de simultanéité)Il existe deux implémentations open source.
Apache Solr a ConcurrentLRUCache: https://lucene.apache.org/solr/3_6_1/org/apache/solr/util/ConcurrentLRUCache.html
Il y a un projet open source pour un ConcurrentLinkedHashMap:
http://code.google.com/p/concurrentlinkedhashmap/
ConcurrentLinkedHashMap
est intéressant. Il prétend avoir été roulé dansMapMaker
de Goyave, mais je ne l'avais pas vu dans les docs. Toute idée de ce qui se passe avec cet effort?Je voudrais envisager d'utiliser java.util.de façon concomitante.PriorityBlockingQueue, avec une priorité déterminée par une "numberOfUses" compteur dans chaque élément. Je serais très, très prudent pour obtenir tous mes synchronisation correcte, comme le "numberOfUses" compteur implique que l'élément ne peut pas être immuable.
L'élément object serait un wrapper pour les objets dans le cache:
Espère que cette aide .
LRU Cache peut être mis en œuvre à l'aide d'un ConcurrentLinkedQueue et un ConcurrentHashMap qui peut être utilisé dans le multithreading scénario. La tête de la file d'attente est cet élément qui a été mis sur la file d'attente la plus longue de temps. La queue de la file d'attente est cet élément qui a été mis sur la file d'attente la plus courte de temps. Lorsqu'un élément de la Carte, on peut l'enlever de la LinkedQueue et l'insérer à la queue.
put
.Voici ma mise en œuvre pour la LRU. J'ai utilisé PriorityQueue, qui fonctionne essentiellement comme FIFO et pas thread-safe.
Utilisé Comparateur basé sur le temps de la création et sur la base effectue la commande
des pages pour le moins récemment utilisé le temps.
Pages pour examen : 2, 1, 0, 2, 8, 2, 4
Ajout de la Page dans le cache est : 2
Ajout de la Page dans le cache est : 1
Ajout de la Page dans le cache est : 0
Page: 2 déjà exisit dans le cache. Dernier accès le temps de mise à jour
Faute de Page, PAGE: 1, Remplacé par PAGE: 8
Ajout de la Page dans le cache est : 8
Page: 2 déjà exisit dans le cache. Dernier accès le temps de mise à jour
Faute de Page, de la PAGE: 0, Remplacé par PAGE: 4
Ajout de la Page dans le cache est : 4
SORTIE
LRUCache Pages
-------------
PageName: 8, PageCreationTime: 1365957019974
PageName: 2, PageCreationTime: 1365957020074
PageName: 4, PageCreationTime: 1365957020174
entrez le code ici
Voici mon testés meilleure exécution simultanée de cache LRU mise en œuvre sans synchronisé bloc:
}
C'est la LRU cache que j'utilise, qui encapsule une LinkedHashMap et poignées de simultanéité avec un simple synchroniser verrouillage de garder le juteux spots. Il "touche" éléments, car ils sont utilisés de telle sorte qu'ils deviennent de la "fraîcheur" de l'élément nouveau, de sorte qu'il est en fait LRU. J'ai également eu l'exigence de mes éléments ayant une durée de vie minimale, que l'on peut également penser que les "temps d'inactivité maximum autorisés", alors vous êtes pour l'expulsion.
Cependant, je suis d'accord avec Hank conclusion et a accepté de répondre-si je suis en commençant ce nouveau aujourd'hui, j'avais découvrez la Goyave est
CacheBuilder
.Bien pour un cache, vous serez généralement en regardant un morceau de données via un serveur proxy de l'objet, (une URL, String....) si l'interface de sage, vous allez vouloir une carte. mais pour le coup les choses que vous voulez une file d'attente comme structure. En interne, je voudrais maintenir deux structures de données, une Priorité de la File d'attente et une HashMap. heres une mise en œuvre qui devrait être capable de tout faire en O(1) fois.
Voici une classe que je fouettée assez rapide:
Voici comment cela fonctionne. Les clés sont stockées dans une liste liée avec la plus ancienne des touches à l'avant de la liste (nouvelles clés aller à l'arrière) lorsque vous avez besoin de "éjection" quelque chose que vous venez de pop hors de l'avant de la file d'attente, puis utilisez la touche pour supprimer la valeur de la carte. Quand un élément reçoit référencés à vous de prendre la ValueHolder de la carte, puis utilisez la emplacement_file variable pour supprimer la clé à partir de son emplacement actuel dans la file d'attente, puis le mettre à l'arrière de la file d'attente (c'est à présent le plus récemment utilisé). L'ajout de choses est à peu près la même.
Je suis sûr que theres une tonne d'erreurs ici et je n'ai pas mis en place de la synchronisation. mais cette classe fournira O(1) en ajoutant dans le cache, O(1) suppression d'éléments anciens, et O(1) la récupération des éléments du cache. Même une simple synchronisation (juste synchroniser chaque méthode publique) serait encore peu de verrouillage en raison du moment de l'exécution. Si quelqu'un a des intelligent de synchronisation des astuces, je serais très intéressé. Aussi, je suis sûr qu'il ya quelques optimisations supplémentaires que vous pourriez mettre en œuvre à l'aide de la maxsize variable par rapport à la carte.
LinkedHashMap
+Collections.synchronizedMap()
mise en œuvre?Ont un coup d'oeil à ConcurrentSkipListMap. Il devrait vous donner log(n) le temps pour les tests et la suppression d'un élément si elle figure déjà dans le cache, et de la constante de temps pour re-ajouter.
Vous auriez juste besoin de quelques contre-etc et l'enveloppe de l'élément de la force de commande de la LRU, de la commande et assurent récente de la substance est rejetée lorsque le cache est plein.
ConcurrentSkipListMap
fournir une certaine facilité de mise en œuvre de bénéficier de plus deConcurrentHashMap
, ou est-ce simplement un cas d'éviter des cas pathologiques?ConcurrentSkipListMap
mise en œuvre, je voudrais créer une nouvelle mise en œuvre de laMap
interface que les délégués àConcurrentSkipListMap
et effectue une sorte d'emballage, de sorte que l'arbitraire des types de clés sont enveloppés dans un type qui est facilement triés sur la base du dernier accès?Voici mon court de mise en place, merci de les critiquer ou de les améliorer!
Voici ma propre mise en œuvre de ce problème
simplelrucache fournit des threads, très simple, non-distribués LRU, la mise en cache avec un TTL de soutien. Il propose deux implémentations:
Vous pouvez le trouver ici: http://code.google.com/p/simplelrucache/
Je suis à la recherche d'une meilleure LRU cache à l'aide de code Java. Est-il possible pour vous de partager votre Java LRU cache de code à l'aide de
LinkedHashMap
etCollections#synchronizedMap
? Actuellement, je suis en utilisantLRUMap implements Map
et le code fonctionne bien, mais je suisArrayIndexOutofBoundException
sur les tests de charge à l'aide de 500 utilisateurs sur la méthode ci-dessous. La méthode déplace l'objet récent à l'avant de la file d'attente.get(Object key)
etput(Object key, Object value)
les appels de méthode ci-dessusmoveToFront
méthode.Voulais ajouter un commentaire à la réponse donnée par Hank mais je ne suis pas capable de le faire - merci de le traiter comme commentaire
LinkedHashMap maintient l'accès et de commande ainsi basée sur le paramètre passé dans son constructeur
Il garde doublement rayé de la liste pour le maintien de l'ordre (Voir LinkedHashMap.D'entrée)
@Pacerier il est exact que LinkedHashMap maintient le même ordre d'itération si l'élément est ajouté à nouveau, mais c'est seulement dans le cas de la commande d'insertion de mode.
c'est ce que j'ai trouvé en java docs de LinkedHashMap.L'entrée de l'objet
cette méthode prend soin de déplacement récemment accédé à l'élément à la fin de la liste. Donc dans l'ensemble LinkedHashMap est la meilleure structure de données pour la mise en œuvre de LRUCache.
Une autre pensée, et même une simple mise en œuvre à l'aide de LinkedHashMap collection de Java.
LinkedHashMap méthode fournie removeEldestEntry et qui peut être remplacée dans la manière citée en exemple. Par défaut, la mise en œuvre de cette structure de collecte est faux. Si c'est vrai et la taille de cette structure va au-delà de la capacité initiale de l'aîné ou plus éléments seront supprimés.
Nous pouvons avoir une pageno et le contenu de la page dans mon cas pageno est entier et au contenu de la page j'ai gardé le numéro de page des valeurs de chaîne.
Suite de ci-dessus exécution de code est comme suit:
À la suite de la @sanjanab concept (mais après corrections) j'ai fait ma version de la LRUCache en fournissant aussi le Consommateur qui permet de faire quelque chose avec les éléments supprimés si nécessaire.
Android offre une mise en œuvre d'un Cache LRU. Le code est propre et simple.