1. Introduction
Dans cet article, jetons un coup d'œil à la caféine - une bibliothèque de cache Java haute performance.
Une différence fondamentale entre le cache et la carte est que les caches peuvent recycler les éléments stockés.
La politique de recyclage consiste à supprimer des objets à un moment spécifié. Cette stratégie affecte directement le taux de succès du cache - une caractéristique importante de la bibliothèque de cache.
La caféine fournit un taux de succès presque optimal en raison de son utilisation de la stratégie de recyclage de Window Tinylfu.
2. Dépendance
Nous devons ajouter la dépendance de la caféine dans pom.xml:
<dependency> <proupId> com.github.ben-manes.caffeine </rom groupeid> <Artifactid> Caffeine </ artifactid> <version> 2.5.5 </-version> </Dependency>
Vous pouvez trouver la dernière version de la caféine sur Maven Central.
3. Remplissez le cache
Jetons un coup d'œil aux trois stratégies de remplissage de cache de la caféine: manuelle, chargement synchrone et chargement asynchrone.
Tout d'abord, nous écrivons une classe pour que le type de valeur soit stocké dans le cache:
classe DataObject {données de chaîne finale privée; Int statique privé Int objetCounter = 0; // constructeurs standard / getters public static dataObject get (String data) {objectCounter ++; renvoyer un nouveau DataObject (données); }}3.1. Remplissage manuel
Dans cette stratégie, nous mettons manuellement la valeur dans le cache avant de la récupérer.
Initialisons le cache:
Cache <string, dataObject> cache = caaffeine.newbuilder () .expirefterWrite (1, timeunit.minutes) .MaxiMumSize (100) .build ();
Maintenant, nous pouvons utiliser la méthode getIFPresent pour obtenir certaines valeurs du cache. Si cette valeur n'existe pas dans le cache, cette méthode renvoie NULL:
String key = "a"; dataObject dataObject = cache.getIfPresent (key); AssertNull (dataObject);
Nous pouvons utiliser la méthode de put pour remplir manuellement le cache:
cache.put (key, dataObject); dataObject = cache.GetIfPresent (key); AssertNotNull (DataObject);
Nous pouvons également utiliser la méthode GET pour obtenir la valeur, qui passe une fonction avec la touche de paramètre comme paramètre. Si la clé n'existe pas dans le cache, la fonction sera utilisée pour fournir une valeur de secours, qui est insérée dans le cache après le calcul:
dataObject = cache .get (key, k -> dataObject.get ("data for a")); AssertNotNull (DataObject); asserTequals ("données pour A", dataObject.getData ());La méthode GET peut effectuer des calculs atomiquement. Cela signifie que vous ne faites le calcul qu'une seule fois - même si plusieurs threads demandent la valeur en même temps. C'est pourquoi l'utilisation de Get est meilleure que Getifpresent.
Parfois, nous devons invalider manuellement certaines valeurs mises en cache:
cache.invalidate (key); dataObject = cache.GettifPresent (key); AssertNull (dataObject);
3.2. Chargement synchrone
Cette méthode de chargement du cache utilise une méthode GET avec une stratégie manuelle similaire à la fonction utilisée pour initialiser les valeurs. Voyons comment l'utiliser.
Tout d'abord, nous devons initialiser le cache:
ChargeingCache <String, DataObject> Cache = Caffeine.NewBuilder () .MaxiMUMSize (100) .ExpirefterWrite (1, timeunit.Minutes) .Build (k -> dataObject.get ("Data for" + K));Nous pouvons maintenant utiliser la méthode GET pour récupérer la valeur:
DataObject dataObject = cache.get (key); AssertNotNull (DataObject); asserTequals ("données pour" + clé, dataObject.getData ());Nous pouvons également utiliser la méthode GetAll pour obtenir un ensemble de valeurs:
Map <string, dataObject> dataObjectMap = cache.getall (arrays.aslist ("a", "b", "c")); asserTequals (3, dataObjectMap.size ());Récupérer les valeurs de la fonction d'initialisation du backend sous-jacente transmise à la méthode de construction. Cela permet d'utiliser le cache comme façade principale d'accès aux valeurs.
3.3. Chargement asynchrone
Cette politique fait la même chose qu'auparavant, mais effectue l'opération de manière asynchrone et renvoie une transition complète contenant la valeur:
AsyncloadingCache <String, dataObject> cache = caffeine.newbuilder () .maximumSize (100) .expirefterwrite (1, timeunit.minutes) .buildasync (k -> dataObject.get ("data for" + k));Nous pouvons utiliser les méthodes GET et GETALL de la même manière, en tenant compte du fait qu'ils renvoient une transition complète:
String key = "a"; cache.get (key) .thenAccept (dataObject -> {assertnotnull (dataObject); asserTequals ("data for" + key, dataObject.getData ());}); cache.getall (arrays.aslist ("a", "b", "c"))) .thenAccept (dataObjectMap -> asserTequals (3, dataObjectMap.size ()));CompleteFuture a de nombreuses API utiles et vous pouvez en obtenir plus dans cet article.
4. Récupération de valeur
La caféine a trois stratégies de récupération de valeur: basée sur la taille, basée sur le temps et basée sur les références.
4.1. Recyclage en fonction de la taille
Cette méthode de recyclage suppose que le recyclage se produit lorsque la limite de taille du cache configurée est dépassée. Il existe deux façons d'obtenir la taille: compter l'objet dans le cache ou obtenir le poids.
Voyons comment calculer les objets dans le cache. Lorsque le cache est initialisé, sa taille est égale à zéro:
ChargingCache <String, dataObject> cache = caffeine.newbuilder () .maximumSize (1) .build (k -> dataObject.get ("data for" + k)); asserTequals (0, cache.simatedSize ());Lorsque nous ajoutons une valeur, la taille augmente considérablement:
cache.get ("a"); asserTequals (1, cache.simatedSize ());Nous pouvons ajouter la deuxième valeur au cache, ce qui entraîne la suppression de la première valeur:
cache.get ("b"); cache.cleanup (); asserTequals (1, cache.simatedSize ());Il convient de mentionner qu'avant d'obtenir la taille du cache, nous appelons la méthode de nettoyage. En effet, le recyclage du cache est exécuté de manière asynchrone, et cette approche aide à attendre que le recyclage se termine.
Nous pouvons également passer une fonction de pesée pour obtenir la taille du cache:
ChargeingCache <String, DataObject> Cache = Caffeine.NewBuilder () .MaxiMumweight (10) .Weighter ((k, v) -> 5) .build (k -> dataObject.get ("data for" + k)); asserTequals (0, cache.simatedSize ()); cache.get ("a"); asserTequals (1, cache.simatedSize ()); cache.get ("b"); asserTequals (2, cache.simatedSize ());Lorsque le poids dépasse 10, la valeur est supprimée du cache:
cache.get ("c"); cache.cleanup (); asserTequals (2, cache.simatedSize ());4.2. Basé sur la récupération du temps
Cette stratégie de recyclage est basée sur le temps d'expiration de l'entrée, et il existe trois types:
Configurons la stratégie d'expiration post-accès à l'aide de la méthode ExpireterAccess:
ChargeingCache <String, DataObject> Cache = Caffeine.NewBuilder () .ExpirefterAccess (5, timeUnit.Minutes) .Build (k -> dataObject.get ("Données pour" + k));Pour configurer la stratégie d'expiration post-écriture, nous utilisons la méthode ExpireterWrite:
cache = caffeine.newbuilder () .expirefterwrite (10, timeunit.seconds) .weakkeys () .weakValues () .build (k -> dataObject.get ("data for" + k));Pour initialiser une stratégie personnalisée, nous devons implémenter l'interface d'expiration:
cache = cafeine.newbuilder (). Expireter (new Expiry <String, dataObject> () {@Override public long expirefterCreate (string key, dataobject value, long currenttime) {return value.getData (). Length () * 1000;} @override public long expirerefterUpdate (string key CurrentDuration;} @Override public long expirefterRead (String Key, DataObject, Long Currenttime, Long CurrentDuration) {return CurrentDuration;}}).4.3. Recyclage basé sur la référence
Nous pouvons configurer le cache pour activer la collecte des ordures de valeurs de clés mises en cache. Pour ce faire, nous configurons la clé et la valeur en tant que références faibles, et nous ne pouvons configurer que des références douces pour la collecte des ordures.
Lorsqu'il n'y a pas de références fortes à l'objet, l'utilisation de faiblesses peut permettre une collecte d'objets d'ordures. Softreference permet aux objets de collecter des ordures basés sur la politique mondiale de JVM la moins utilisée. Pour plus de détails sur les citations de Java, voir ici.
Nous devons activer chaque option en utilisant Cafeine.WeakKeys (), Caffeine.WeakValues () et Caffeine.SoftValues ():
ChargingCache <String, dataObject> cache = caaffeine.newbuilder () .expirefterwrite (10, timeunit.seconds) .weakkeys () .weakValues () .build (k -> dataObject.get ("data for" + k)); cache = caffeine.newbuilder () .expirefterwrite (10, timeunit.seconds) .softValues () .build (k -> dataObject.get ("data for" + k));5. actualiser
Le cache peut être configuré pour rafraîchir automatiquement l'entrée après une période définie. Voyons comment utiliser la méthode RefreshafterWrite:
Cafeine.newBuilder () .refreshafterwrite (1, timeunit.minutes) .build (k -> dataObject.get ("Données pour" + k));Ici, nous devons comprendre la différence entre l'expiration et la rafraîchissement. Lorsqu'une entrée expirée est demandée, l'exécution se bloque jusqu'à ce que la fonction de construction calcule la nouvelle valeur.
Cependant, si l'entrée peut être actualisée, le cache renvoie une vieille valeur et recharge la valeur de manière asynchrone.
6. Statistiques
La caféine a un moyen d'enregistrer l'utilisation du cache:
ChargingCache <String, dataObject> cache = caaffeine.newbuilder () .maximumSize (100) .RecordStats () .Build (k -> dataObject.get ("data for" + k)); cache.get ("a"); cache.get ("a"); asserTequals (1, cache.stats (). hitCount ()); asserTequals (1, cache.stats (). missCount ());Nous pouvons également transmettre un fournisseur RecordStats pour créer une implémentation de StatScounter. Cet objet est poussé à chaque changement lié aux statistiques.
7. Conclusion
Dans cet article, nous connaissons la bibliothèque de cache de caféine de Java. Nous avons vu comment configurer et remplir le cache, et comment choisir la politique d'expiration ou de rafraîchissement appropriée en fonction de nos besoins.
Le code source des exemples de cet article peut être trouvé sur GitHub.
Ce qui précède est tout le contenu de cet article. J'espère que cela sera utile à l'apprentissage de tous et j'espère que tout le monde soutiendra davantage Wulin.com.