Guava Cache
1. Áttekintés
Ebben az oktatóanyagban megnézzük a Guava Cache megvalósítás - alapvető használat, kilakoltatási irányelvek, a gyorsítótár frissítése és néhány érdekes tömeges művelet.
Végül megvizsgáljuk a gyorsítótár által küldhető eltávolítási értesítések használatát.
2. A Guava Cache használata
Kezdjük egy egyszerű példával - tegyük gyorsítótárba a nagybetűs alakját Húr példányok.
Először létrehozzuk a CacheLoader - a gyorsítótárban tárolt érték kiszámítására szolgál. Ebből a praktikusat fogjuk használni CacheBuilder a gyorsítótárunk felépítése a megadott specifikációk alapján:
@Test public void whenCacheMiss_thenValueIsComputed () {CacheLoader betöltő; loader = new CacheLoader () {@Override public String load (String key) {return key.toUpperCase (); }}; LoadingCache gyorsítótár; cache = CacheBuilder.newBuilder (). build (betöltő); assertEquals (0, cache.size ()); assertEquals ("HELLO", cache.getUnchecked ("hello")); assertEquals (1, cache.size ()); }
Figyelje meg, hogy nincs-e érték a "hello" kulcs gyorsítótárában - és így az érték kiszámításra és gyorsítótárba kerül.
Vegye figyelembe azt is, hogy a getUnchecked () művelet - ez kiszámítja és betölti az értéket a gyorsítótárba, ha még nem létezik.
3. Kilakoltatási irányelvek
Minden gyorsítótárnak el kell távolítania az értékeket valamikor. Beszéljük meg az értékek gyorsítótárból történő kiürítésének mechanizmusát - különböző kritériumok segítségével.
3.1. A kilakoltatás méret szerint
Tudunk korlátozza a gyorsítótár méretét felhasználásával maximumSize (). Ha a gyorsítótár eléri a korlátot, a legrégebbi elemeket kilakoltatják.
A következő kódban a gyorsítótár méretét 3 rekordra korlátozzuk:
@Test public void whenCacheReachMaxSize_thenEviction () {CacheLoader betöltő; loader = new CacheLoader () {@Override public String load (String key) {return key.toUpperCase (); }}; LoadingCache gyorsítótár; cache = CacheBuilder.newBuilder (). maximumSize (3) .build (betöltő); cache.getUnchecked ("első"); cache.getUnchecked ("második"); cache.getUnchecked ("harmadik"); cache.getUnchecked ("tovább"); assertEquals (3, cache.size ()); assertNull (cache.getIfPresent ("első")); assertEquals ("FORTH", cache.getIfPresent ("tovább")); }
3.2. Súly szerinti kilakoltatás
Azt is megtehetjük korlátozza a gyorsítótár méretét egyedi súlyfüggvény használatával. A következő kódban a hossz egyedi súlyfüggvényünkként:
@Test public void whenCacheReachMaxWeight_thenEviction () {CacheLoader betöltő; loader = new CacheLoader () {@Orride public String load (String key) {return key.toUpperCase (); }}; Mérleg súlyaByLength; weightByLength = new Weigher () {@Orride public int weight (String key, String value) {return value.length (); }}; LoadingCache gyorsítótár; cache = CacheBuilder.newBuilder () .maximumWeight (16) .weigher (weightByLength) .build (loader); cache.getUnchecked ("első"); cache.getUnchecked ("második"); cache.getUnchecked ("harmadik"); cache.getUnchecked ("utolsó"); assertEquals (3, cache.size ()); assertNull (cache.getIfPresent ("első")); assertEquals ("UTOLSÓ", cache.getIfPresent ("utolsó")); }
Megjegyzés: A gyorsítótár egynél több rekordot is eltávolíthat, hogy helyet biztosítson egy új nagynak.
3.3. Idõ szerinti kilakoltatás
A régi rekordok kilakoltatásán kívül használhatunk időt is. A következő példában a gyorsítótárunkat testre szabjuk távolítsa el a 2 másodpercig tétlen rekordokat:
@Test public void, amikorEntryIdle_thenEviction () az InterruptedException {CacheLoader betöltőt dobja; loader = new CacheLoader () {@Orride public String load (String key) {return key.toUpperCase (); }}; LoadingCache gyorsítótár; cache = CacheBuilder.newBuilder () .expireAfterAccess (2, TimeUnit.MILLISECONDS) .build (betöltő); cache.getUnchecked ("hello"); assertEquals (1, cache.size ()); cache.getUnchecked ("hello"); Szál.alszik (300); cache.getUnchecked ("teszt"); assertEquals (1, cache.size ()); assertNull (cache.getIfPresent ("hello")); }
Azt is megtehetjük a teljes élettartamuk alapján kiírják a nyilvántartásokat. A következő példában a gyorsítótár 2 ms elteltével eltávolítja a rekordokat:
@Test public void, amikorEntryLiveTimeExpire_thenEviction () az InterruptedException {CacheLoader betöltőt dobja; loader = new CacheLoader () {@Orride public String load (String key) {return key.toUpperCase (); }}; LoadingCache gyorsítótár; cache = CacheBuilder.newBuilder () .expireAfterWrite (2, TimeUnit.MILLISECONDS) .build (betöltő); cache.getUnchecked ("hello"); assertEquals (1, cache.size ()); Szál.alszik (300); cache.getUnchecked ("teszt"); assertEquals (1, cache.size ()); assertNull (cache.getIfPresent ("hello")); }
4. Gyenge kulcsok
Ezután nézzük meg, hogyan lehet a gyorsítótár-kulcsokat gyenge referenciákkal ellátni - lehetővé téve a szemétszedő számára, hogy összegyűjtse azokat a gyorsítótár-kulcsokat, amelyekre máshol nem hivatkoznak.
Alapértelmezés szerint mind a gyorsítótár-kulcsok, mind az értékek erős referenciákkal rendelkeznek, de a gyorsítótárunkat gyenge referenciák használatával tárolhatjuk gyenge kulcsok () mint a következő példában:
@Test public void whenWeakKeyHasNoRef_thenRemoveFromCache () {CacheLoader betöltő; loader = new CacheLoader () {@Override public String load (String key) {return key.toUpperCase (); }}; LoadingCache gyorsítótár; cache = CacheBuilder.newBuilder (). silpKeys (). build (betöltő); }
5. Lágy értékek
Használatával engedélyezhetjük, hogy a szemétszedő összegyűjtse a gyorsítótárazott értékeinket softValues () mint a következő példában:
@Test public void whenSoftValue_thenRemoveFromCache () {CacheLoader betöltő; loader = new CacheLoader () {@Override public String load (String key) {return key.toUpperCase (); }}; LoadingCache gyorsítótár; cache = CacheBuilder.newBuilder (). softValues (). build (betöltő); }
Megjegyzés: Számos puha hivatkozás befolyásolhatja a rendszer teljesítményét - előnyösebb használni maximumSize ().
6. Fogantyú nulla Értékek
Most nézzük meg, hogyan kell kezelni a gyorsítótárat nulla értékek. Alapértelmezés szerint, Guava Cache kivételt dob, ha megpróbálja betölteni a nulla érték - mivel nincs értelme a gyorsítótárba tenni a nulla.
De ha nulla érték jelent valamit a kódodban, akkor jól használhatod a Választható osztály, mint a következő példában:
@Test public void whenNullValue_thenOptional () {CacheLoader rakodó; loader = új CacheLoader() {@Override public Opcionális betöltés (karakterlánc kulcs) {return Optional.fromNullable (getSuffix (kulcs)); }}; LoadingCache gyorsítótár; cache = CacheBuilder.newBuilder (). build (betöltő); assertEquals ("txt", cache.getUnchecked ("text.txt"). get ()); assertFalse (cache.getUnchecked ("hello"). isPresent ()); } privát String getSuffix (végső String Str) {int lastIndex = str.lastIndexOf ('.'); if (lastIndex == -1) {return null; } return str.substring (lastIndex + 1); }
7. Frissítse a gyorsítótárat
Ezután nézzük meg, hogyan frissíthetjük a gyorsítótár értékeinket.
7.1. Manuális frissítés
Egyetlen kulcsot manuálisan frissíthetünk a segítségével LoadingCache.refresh (kulcs).
Karakterlánc értéke = loadingCache.get ("kulcs"); loadingCache.refresh ("kulcs");
Ez kényszeríteni fogja a CacheLoader betölteni az új értéket a kulcs.
Az új érték sikeres betöltéséig az előző értéke kulcs visszaadja a get (kulcs).
7.2. Automatikus frissítés
Tudjuk használni CacheBuilder.refreshAfterWrite (időtartam) a gyorsítótárazott értékek automatikus frissítéséhez.
@Test public void whenLiveTimeEnd_thenRefresh () {CacheLoader betöltő; loader = new CacheLoader () {@Override public String load (String key) {return key.toUpperCase (); }}; LoadingCache gyorsítótár; cache = CacheBuilder.newBuilder () .refreshAfterWrite (1, TimeUnit.MINUTES) .build (betöltő); }
Fontos ezt megérteni refreshAfterWrite (időtartam) csak kulcsot készít választható a frissítéshez a megadott időtartam után. Az érték valójában csak akkor frissül, ha egy megfelelő bejegyzést lekérdez get (kulcs).
8. Töltse be előre a gyorsítótárat
A. Használatával több rekordot is beilleszthetünk a gyorsítótárunkba putAll () módszer. A következő példában több rekordot adunk a gyorsítótárunkba az a használatával Térkép:
@Test public void whenPreloadCache_thenUsePutAll () {CacheLoader loader; loader = new CacheLoader () {@Orride public String load (String key) {return key.toUpperCase (); }}; LoadingCache gyorsítótár; cache = CacheBuilder.newBuilder (). build (betöltő); Térképtérkép = új HashMap (); map.put ("első", "ELSŐ"); map.put ("második", "MÁSODIK"); cache.putAll (térkép); assertEquals (2, cache.size ()); }
9. RemovalNotification
Néha meg kell tennie bizonyos műveleteket, amikor egy rekordot eltávolít a gyorsítótárból; szóval, beszéljük meg RemovalNotification.
Regisztrálhatunk a RemovalListener értesítéseket kap a rekord eltávolításáról. Az eltávolítás okához is hozzáférhetünk - a getCause () módszer.
A következő mintában a RemovalNotification akkor érkezik, amikor a gyorsítótár negyedik eleme a mérete miatt:
@Test public void whenEntryRemovedFromCache_thenNotify () {CacheLoader betöltő; loader = new CacheLoader () {@Orride public String load (final String key) {return key.toUpperCase (); }}; RemovalListener hallgató; listener = new RemovalListener () {@Orride public void onRemoval (RemovalNotification n) {if (n.wasEvicted ()) {String reason = n.getCause (). name (); assertEquals (RemovalCause.SIZE.toString (), oka); }}}; LoadingCache gyorsítótár; cache = CacheBuilder.newBuilder () .maximumSize (3) .removalListener (figyelő) .build (betöltő); cache.getUnchecked ("első"); cache.getUnchecked ("második"); cache.getUnchecked ("harmadik"); cache.getUnchecked ("utolsó"); assertEquals (3, cache.size ()); }
10. Megjegyzések
Végül íme néhány további gyors megjegyzés a guava gyorsítótár megvalósításáról:
- menetbiztos
- az értékeket manuálisan beillesztheti a gyorsítótárba a put (kulcs, érték)
- segítségével mérheti a gyorsítótár teljesítményét CacheStats ( találati arány(), missRate (), ..)
11. Következtetés
A Guava Cache sok használati esetét átéltük ebben az oktatóanyagban - az egyszerű használattól kezdve az elemek kilakoltatásáig, a gyorsítótár frissítéséig és előzetes betöltéséig, valamint az eltávolítási értesítésekig.
Szokás szerint az összes példa megtalálható a GitHub-on.