Bevezetés a koffeinbe
1. Bemutatkozás
Ebben a cikkben megnézzük a koffeint - a nagy teljesítményű gyorsítótár-könyvtár Java számára.
Egy alapvető különbség a gyorsítótár és az a között Térkép az, hogy a gyorsítótár kiüríti a tárolt elemeket.
An a kilakoltatási politika dönti el, mely objektumokat kell törölni bármikor. Ez a politika közvetlenül befolyásolja a gyorsítótár találati arányát - a könyvtárak gyorsítótárazásának alapvető jellemzője.
A koffein a Ablak TinyLfu kilakoltatási politika, amely a közel az optimális találati arány.
2. Függőség
Hozzá kell adnunk a koffein függőség a mi pom.xml:
com.github.ben-manes.caffeine koffein 2.5.5
Megtalálja a legújabb verzióját koffein a Maven Central-on.
3. A gyorsítótár feltöltése
Koncentráljunk a koffeinre három stratégia a gyorsítótár-populációhoz: kézi, szinkron és aszinkron betöltés.
Először írjunk egy osztályt azoknak az értéktípusoknak, amelyeket a gyorsítótárunkban tárolunk:
osztály DataObject {private final String adatok; privát statikus int objectCounter = 0; // standard konstruktorok / getterek nyilvános statikus DataObject get (String adatok) {objectCounter ++; return new DataObject (adatok); }}
3.1. Kézi kitöltés
Ebben a stratégiában manuálisan helyezünk értékeket a gyorsítótárba, és később visszakeresjük őket.
Inicializáljuk a gyorsítótárunkat:
Gyorsítótár gyorsítótár = Caffeine.newBuilder () .expireAfterWrite (1, TimeUnit.MINUTES) .maximumSize (100) .build ();
Most, némi értéket kaphatunk a gyorsítótárból a getIfPresent módszer. Ez a módszer visszatér nulla ha az érték nincs a gyorsítótárban:
Karakterlánc = "A"; DataObject dataObject = cache.getIfPresent (kulcs); assertNull (dataObject);
Tudunk töltse fel a gyorsítótárat manuálisan a tedd módszer:
cache.put (kulcs, dataObject); dataObject = cache.getIfPresent (kulcs); assertNotNull (dataObject);
Az értéket a kap módszer, amely a Funkció érvként egy kulccsal együtt. Ezt a függvényt a tartalékérték megadására fogják használni, ha a kulcs nincs a gyorsítótárban, amelyet a számítás után be kell illeszteni a gyorsítótárba:
dataObject = cache .get (kulcs, k -> DataObject.get ("Adatok A-hoz")); assertNotNull (dataObject); assertEquals ("Adatok A-hoz", dataObject.getData ());
A kap módszer a számítást atomszerűen végzi. Ez azt jelenti, hogy a számítás csak egyszer fog elvégezni - még akkor is, ha több szál egyszerre kéri az értéket. Ezért felhasználásával kap előnyösebb, mint getIfPresent.
Néha szükségünk van rá érvénytelenít néhány gyorsítótárazott értéket manuálisan:
cache.invalidate (kulcs); dataObject = cache.getIfPresent (kulcs); assertNull (dataObject);
3.2. Szinkron töltés
A gyorsítótár betöltésének ez a módszere a Funkció, amelyet az értékek inicializálására használunk, hasonlóan a kap a kézi stratégia módszere. Lássuk, hogyan tudjuk ezt felhasználni.
Először is inicializálnunk kell a gyorsítótárat:
LoadingCache cache = Caffeine.newBuilder () .maximumSize (100) .expireAfterWrite (1, TimeUnit.MINUTES) .build (k -> DataObject.get ("Adatok" + k));
Most lekérhetjük az értékeket a kap módszer:
DataObject dataObject = cache.get (kulcs); assertNotNull (dataObject); assertEquals ("Data for" + kulcs, dataObject.getData ());
A. Használatával értékkészletet is kaphatunk getAll módszer:
Map dataObjectMap = cache.getAll (Arrays.asList ("A", "B", "C")); assertEquals (3, dataObjectMap.size ());
Az értékeket az alapul szolgáló háttér-inicializálásból kapjuk le Funkció hogy átadták a épít módszer. Ez lehetővé teszi a gyorsítótár használatát fő homlokzatként az értékek eléréséhez.
3.3. Aszinkron töltés
Ez a stratégia ugyanúgy működik, mint az előző, de aszinkron módon hajtja végre a műveleteket, és visszaadja a CompletableFuture a tényleges érték birtokában:
AsyncLoadingCache cache = Caffeine.newBuilder () .maximumSize (100) .expireAfterWrite (1, TimeUnit.MINUTES) .buildAsync (k -> DataObject.get ("Adatok" + k));
Tudunk használja a kap és getAll mód, ugyanúgy, figyelembe véve azt a tényt, hogy visszatérnek CompletableFuture:
Karakterlánc = "A"; cache.get (kulcs) .theAccept (dataObject -> {assertNotNull (dataObject); assertEquals ("Data for" + kulcs, dataObject.getData ());}); cache.getAll (Arrays.asList ("A", "B", "C")) .thenAccept (dataObjectMap -> assertEquals (3, dataObjectMap.size ()));
CompletableFuture gazdag és hasznos API-val rendelkezik, amelyről ebben a cikkben olvashat bővebben.
4. Értékek kilakoltatása
A koffeinnek van három stratégia az érték kilakoltatásához: méretalapú, időalapú és referencia-alapú.
4.1. Méretalapú kilakoltatás
Ez a típusú kilakoltatás azt feltételezi kilakoltatás történik, ha túllépik a gyorsítótár beállított méretkorlátját. Vannak a méret megadásának két módja - a gyorsítótárban lévő tárgyak számlálása vagy súlyuk megszerzése.
Lássuk, hogyan tudnánk számoljon objektumokat a gyorsítótárban. A gyorsítótár inicializálásakor a mérete egyenlő nulla:
LoadingCache cache = Caffeine.newBuilder () .maximumSize (1) .build (k -> DataObject.get ("Adatok" + k)); assertEquals (0, cache.estimatedSize ());
Érték hozzáadásakor a méret nyilvánvalóan megnő:
cache.get ("A"); assertEquals (1, cache.estimatedSize ());
Hozzáadhatjuk a második értéket a gyorsítótárhoz, ami az első érték eltávolításához vezet:
cache.get ("B"); cache.cleanUp (); assertEquals (1, cache.estimatedSize ());
Érdemes megemlíteni, hogy mi hívja a cleanUp módszer, mielőtt megkapja a gyorsítótár méretét. Ennek oka, hogy a gyorsítótár kiürítését aszinkron módon hajtják végre, és ez a módszer segít megvárni a kilakoltatás befejezését.
Azt is megtehetjük át egy mérlegelőFunkcióa gyorsítótár méretének megszerzéséhez:
LoadingCache cache = Caffeine.newBuilder () .maximumWeight (10) .weigher ((k, v) -> 5) .build (k -> DataObject.get ("Adatok" + k)); assertEquals (0, cache.estimatedSize ()); cache.get ("A"); assertEquals (1, cache.estimatedSize ()); cache.get ("B"); assertEquals (2, cache.estimatedSize ());
Az értékek eltávolításra kerülnek a gyorsítótárból, ha a súly meghaladja a 10-et:
cache.get ("C"); cache.cleanUp (); assertEquals (2, cache.estimatedSize ());
4.2. Időalapú kilakoltatás
Ez a kilakoltatási stratégia az a bejegyzés lejárati ideje alapján és három típusa van:
- A hozzáférés után lejár - a bejegyzés az utolsó olvasás vagy írás bekövetkezte óta eltelt idő leteltével lejár
- Írás után lejár - a bejegyzés az utolsó írás bekövetkezte óta eltelt idő elteltével lejár
- Egyéni házirend - a lejárati időt minden egyes bejegyzéshez külön számítja ki a Lejárat végrehajtás
Konfiguráljuk az expire-after-access stratégiát a expireAfterAccess módszer:
LoadingCache cache = Caffeine.newBuilder () .expireAfterAccess (5, TimeUnit.MINUTES) .build (k -> DataObject.get ("Adatok" + k));
Az expire-after-write stratégia konfigurálásához a expireAfterWrite módszer:
gyorsítótár = Caffeine.newBuilder () .expireAfterWrite (10, TimeUnit.SECONDS) .weakKeys () .weakValues () .build (k -> DataObject.get ("Data for + k));
Egyéni házirend inicializálásához végre kell hajtanunk a Lejárat felület:
cache = Caffeine.newBuilder (). expireAfter (new Expiry () {@Orride public long expireAfterCreate (String kulcs, DataObject érték, hosszú currentTime) {return value.getData (). length () * 1000;} @Override public long expireAfterUpdate (Karaktersorozatkulcs, DataObject érték, hosszú currentTime, hosszú currentDuration) {return currentDuration;} @Orride public long expireAfterRead (Stringkulcs, DataObject érték, long currentTime, long currentDuration) {return currentDuration;}}. .get ("Adatok a" + k számára ");
4.3. Referencia alapú kilakoltatás
Konfigurálhatjuk a gyorsítótárunkat az engedélyezéshez a gyorsítótár kulcsainak és / vagy értékeinek szemétgyűjtése. Ehhez konfigurálnánk a WeakRefence kulcsokhoz és értékekhez egyaránt, és konfigurálhatjuk a SoftReference csak értékek szemétgyűjtésére.
A WeakRefence A használat lehetővé teszi az objektumok szemétgyűjtését, ha nincsenek erős utalások az objektumra. SoftReference lehetővé teszi az objektumok szemétszedését a JVM globálisan legkevésbé használt stratégiája alapján. További részletek a Java-hivatkozásokról itt találhatók.
Használnunk kellene Caffeine.weakKeys (), Caffeine.weakValues (), és Caffeine.softValues () az egyes lehetőségek engedélyezéséhez:
LoadingCache cache = Caffeine.newBuilder () .expireAfterWrite (10, TimeUnit.SECONDS) .weakKeys () .weakValues () .build (k -> DataObject.get ("Adatok" + k)); cache = Caffeine.newBuilder () .expireAfterWrite (10, TimeUnit.SECONDS) .softValues () .build (k -> DataObject.get ("Adatok" + k));
5. Frissítő
A gyorsítótár úgy konfigurálható, hogy a bejegyzések meghatározott idő után automatikusan frissüljenek. Nézzük meg, hogyan lehet ezt megtenni a refreshAfterWrite módszer:
Caffeine.newBuilder () .refreshAfterWrite (1, TimeUnit.MINUTES) .build (k -> DataObject.get ("Adatok" + k));
Itt meg kell értenünk a a különbség köztük lejárt utána és refreshAfter. Amikor a lejárt bejegyzést kéri, egy végrehajtás blokkol, amíg az új értéket a build nem számította volna ki Funkció.
De ha a bejegyzés frissíthető, akkor a gyorsítótár régi értéket ad vissza aszinkron módon töltse be újra az értéket.
6. Statisztika
A koffeinnek van eszköze statisztikák rögzítése a gyorsítótár használatáról:
LoadingCache cache = Caffeine.newBuilder () .maximumSize (100) .recordStats () .build (k -> DataObject.get ("Adatok a + k számára)"; cache.get ("A"); cache.get ("A"); assertEquals (1, cache.stats (). hitCount ()); assertEquals (1, cache.stats (). missCount ());
Mi is átmehetünk recordStats szállító, amely létrehozza a StatsCounter. Ez az objektum minden statisztikához kapcsolódó változással meg lesz tolva.
7. Következtetés
Ebben a cikkben megismerkedtünk a Java koffein gyorsítótár könyvtárával. Láttuk, hogyan kell konfigurálni és feltölteni a gyorsítótárat, valamint hogyan lehet megfelelő lejárati vagy frissítési házirendet választani az igényeinknek megfelelően.
Az itt látható forráskód elérhető a Githubon.