Guava Cache

1. Oversikt

I denne opplæringen tar vi en titt på Guava Cache implementering - grunnleggende bruk, utkastelsespolicyer, oppdatering av hurtigbufferen og noen interessante bulkoperasjoner.

Til slutt vil vi se på bruken av fjerningsmeldingene hurtigbufferen kan sende ut.

2. Hvordan bruke Guava Cache

La oss starte med et enkelt eksempel - la oss cache store bokstaver av String tilfeller.

Først skal vi lage CacheLoader - brukes til å beregne verdien som er lagret i hurtigbufferen. Fra dette bruker vi det praktiske CacheBuilder for å bygge cachen vår ved hjelp av spesifikasjonene:

@Test offentlig ugyldig nårCacheMiss_thenValueIsComputed () {CacheLoader loader; loader = ny CacheLoader () {@Override public String load (String key) {return key.toUpperCase (); }}; LoadingCache cache; cache = CacheBuilder.newBuilder (). build (loader); assertEquals (0, cache.size ()); assertEquals ("HELLO", cache.getUnchecked ("hallo")); assertEquals (1, cache.size ()); }

Legg merke til hvordan det ikke er noen verdi i hurtigbufferen for "hei" -tasten - og verdien blir så beregnet og bufret.

Vær også oppmerksom på at vi bruker bli ukontrollert () operasjon - dette beregner og laster verdien inn i hurtigbufferen hvis den ikke allerede eksisterer.

3. Utkastelsespolitikker

Hver hurtigbuffer må fjerne verdier på et eller annet tidspunkt. La oss diskutere mekanismen for å kaste ut verdier ut av hurtigbufferen - ved å bruke forskjellige kriterier.

3.1. Utsetting etter størrelse

Vi kan begrense størrelsen på cachen vår ved hjelp av maximumSize (). Hvis hurtigbufferen når grensen, blir de eldste elementene kastet ut.

I følgende kode begrenser vi hurtigbufferstørrelsen til 3 poster:

@Test offentlig ugyldig nårCacheReachMaxSize_thenEviction () {CacheLoader loader; loader = new CacheLoader () {@Override public String load (String key) {return key.toUpperCase (); }}; LoadingCache cache; cache = CacheBuilder.newBuilder (). maximumSize (3) .build (loader); cache.getUnchecked ("første"); cache.getUnchecked ("andre"); cache.getUnchecked ("tredje"); cache.getUnchecked ("frem"); assertEquals (3, cache.size ()); assertNull (cache.getIfPresent ("første")); assertEquals ("FORTH", cache.getIfPresent ("frem")); }

3.2. Utsetting etter vekt

Vi kan også begrense bufferstørrelsen ved hjelp av en tilpasset vektfunksjon. I den følgende koden bruker vi lengde som vår tilpassede vektfunksjon:

@Test offentlig ugyldig nårCacheReachMaxWeight_thenEviction () {CacheLoader loader; loader = ny CacheLoader () {@Override public String load (String key) {return key.toUpperCase (); }}; Veiere veiByLengde; weighByLength = new Weigher () {@Override public int weigh (String key, String value) {return value.length (); }}; LoadingCache cache; cache = CacheBuilder.newBuilder () .maximumWeight (16) .veigher (weighByLength) .build (loader); cache.getUnchecked ("første"); cache.getUnchecked ("andre"); cache.getUnchecked ("tredje"); cache.getUnchecked ("siste"); assertEquals (3, cache.size ()); assertNull (cache.getIfPresent ("første")); assertEquals ("SISTE", cache.getIfPresent ("siste")); }

Merk: Cachen kan fjerne mer enn én post for å gi plass til en ny stor.

3.3. Eviction by Time

Foruten å bruke størrelse for å kaste ut gamle poster, kan vi bruke tid. I det følgende eksemplet tilpasser vi cachen vår til fjerne poster som har vært inaktive i 2 ms:

@Test offentlig ugyldig nårEntryIdle_thenEviction () kaster InterruptedException {CacheLoader loader; loader = new CacheLoader () {@Override public String load (String key) {return key.toUpperCase (); }}; LoadingCache cache; cache = CacheBuilder.newBuilder () .expireAfterAccess (2, TimeUnit.MILLISECONDS) .build (laster); cache.getUnchecked ("hei"); assertEquals (1, cache.size ()); cache.getUnchecked ("hei"); Tråd. Søvn (300); cache.getUnchecked ("test"); assertEquals (1, cache.size ()); assertNull (cache.getIfPresent ("hei")); }

Vi kan også kaste ut poster basert på deres totale live tid. I det følgende eksemplet vil hurtigbufferen fjerne postene etter 2 ms lagring:

@Test offentlig ugyldig nårEntryLiveTimeExpire_thenEviction () kaster InterruptedException {CacheLoader loader; loader = new CacheLoader () {@Override public String load (String key) {return key.toUpperCase (); }}; LoadingCache cache; cache = CacheBuilder.newBuilder () .expireAfterWrite (2, TimeUnit.MILLISECONDS) .build (laster); cache.getUnchecked ("hei"); assertEquals (1, cache.size ()); Tråd. Søvn (300); cache.getUnchecked ("test"); assertEquals (1, cache.size ()); assertNull (cache.getIfPresent ("hei")); }

4. Svake taster

Deretter, la oss se hvordan vi kan lage cache-tastene våre med svake referanser - slik at søppeloppsamleren kan samle cache-nøkler som ikke er referert til andre steder.

Som standard har både hurtigbuffertaster og verdier sterke referanser, men vi kan gjøre at hurtigbufferen vår lagrer tastene ved hjelp av svake referanser svake nøkler () som i følgende eksempel:

@Test offentlig ugyldig nårWeakKeyHasNoRef_thenRemoveFromCache () {CacheLoader loader; loader = new CacheLoader () {@Override public String load (String key) {return key.toUpperCase (); }}; LoadingCache cache; cache = CacheBuilder.newBuilder (). weakKeys (). build (loader); }

5. Myke verdier

Vi kan tillate søppeloppsamleren å samle inn våre hurtigbufrede verdier ved å bruke softValues ​​() som i følgende eksempel:

@Test offentlig ugyldig nårSoftValue_thenRemoveFromCache () {CacheLoader loader; loader = new CacheLoader () {@Override public String load (String key) {return key.toUpperCase (); }}; LoadingCache cache; cache = CacheBuilder.newBuilder (). softValues ​​(). build (loader); }

Merk: Mange myke referanser kan påvirke systemytelsen - det er foretrukket å bruke maximumSize ().

6. Håndtak null Verdier

La oss nå se hvordan du skal håndtere cache null verdier. Som standard, Guava Cache vil kaste unntak hvis du prøver å laste inn en null verdi - da det ikke gir mening å cache a null.

Men hvis null verdi betyr noe i koden din, så kan du gjøre god bruk av Valgfri klasse som i følgende eksempel:

@Test offentlig ugyldig nårNullValue_thenOptional () {CacheLoader laster; loader = ny CacheLoader() {@Override public Valgfri belastning (strengnøkkel) {retur Optional.fromNullable (getSuffix (key)); }}; LoadingCache cache; cache = CacheBuilder.newBuilder (). build (loader); assertEquals ("txt", cache.getUnchecked ("text.txt"). get ()); assertFalse (cache.getUnchecked ("hei"). isPresent ()); } privat streng getSuffix (siste strengstreng) {int lastIndex = str.lastIndexOf ('.'); hvis (lastIndex == -1) {return null; } returnere str.substring (lastIndex + 1); }

7. Oppdater hurtigbufferen

La oss deretter se hvordan du kan oppdatere cacheverdiene.

7.1. Manuell oppdatering

Vi kan oppdatere en enkelt nøkkel manuelt ved hjelp av LoadingCache.refresh (nøkkel).

Strengverdi = loadingCache.get ("nøkkel"); loadingCache.refresh ("nøkkel");

Dette vil tvinge CacheLoader for å laste inn den nye verdien for nøkkel.

Inntil den nye verdien er lastet inn, den forrige verdien av nøkkel vil bli returnert av få (nøkkel).

7.2. Automatisk oppdatering

Vi kan bruke CacheBuilder.refreshAfterWrite (varighet) for å automatisk oppdatere hurtigbufrede verdier.

@Test offentlig ugyldig nårLiveTimeEnd_thenRefresh () {CacheLoader loader; loader = new CacheLoader () {@Override public String load (String key) {return key.toUpperCase (); }}; LoadingCache cache; cache = CacheBuilder.newBuilder () .refreshAfterWrite (1, TimeUnit.MINUTES) .build (laster); }

Det er viktig å forstå det refreshAfterWrite (varighet) bare lager en nøkkel kvalifisert for oppdateringen etter den angitte varigheten. Verdien oppdateres faktisk bare når en tilsvarende oppføring blir spurt av få (nøkkel).

8. Last inn hurtigbufferen

Vi kan sette inn flere poster i cachen vår ved hjelp av putt alle() metode. I det følgende eksemplet legger vi til flere poster i cachen vår ved hjelp av a Kart:

@Test offentlig ugyldig nårPreloadCache_thenUsePutAll () {CacheLoader loader; loader = ny CacheLoader () {@Override public String load (String key) {return key.toUpperCase (); }}; LoadingCache cache; cache = CacheBuilder.newBuilder (). build (loader); Kartkart = nytt HashMap (); map.put ("første", "FØRSTE"); map.put ("andre", "ANDRE"); cache.putAll (kart); assertEquals (2, cache.size ()); }

9. FjerningVarsling

Noen ganger må du ta noen handlinger når en post blir fjernet fra hurtigbufferen; så, la oss diskutere FjerningVarsling.

Vi kan registrere en FjerningListener for å få varsler om at en post blir fjernet. Vi har også tilgang til årsaken til fjerningen - via getCause () metode.

I det følgende eksemplet, a FjerningVarsling mottas når det fjerde elementet i hurtigbufferen på grunn av størrelsen:

@Test offentlig ugyldig nårEntryRemovedFromCache_thenNotify () {CacheLoader loader; loader = ny CacheLoader () {@Override public String load (final String key) {return key.toUpperCase (); }}; RemovalListener lytter; listener = new RemovalListener () {@Override public void onRemoval (RemovalNotification n) {if (n.wasEvicted ()) {Strengårsak = n.getCause (). name (); assertEquals (RemovalCause.SIZE.toString (), årsak); }}}; LoadingCache cache; cache = CacheBuilder.newBuilder () .maximumSize (3) .removalListener (lytter) .build (laster); cache.getUnchecked ("første"); cache.getUnchecked ("andre"); cache.getUnchecked ("tredje"); cache.getUnchecked ("siste"); assertEquals (3, cache.size ()); }

10. Merknader

Til slutt, her er noen få raske notater om Guava-cache-implementeringen:

  • den er trådsikker
  • du kan sette inn verdier manuelt i hurtigbufferen ved hjelp av put (nøkkel, verdi)
  • du kan måle cacheytelsen ved hjelp av CacheStats ( treffsrate(), missRate (), ..)

11. Konklusjon

Vi gikk gjennom mange brukstilfeller av Guava Cache i denne opplæringen - fra enkel bruk til utkastelse av elementer, oppdatering og forhåndsinnlasting av hurtigbufferen og varsler om fjerning.

Som vanlig kan du finne alle eksemplene på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found