Class Cache<K,V>

java.lang.Object
com.codename1.backend.Cache<K,V>

public final class Cache<K,V> extends Object

A bounded, process-local application cache: entries limited by count or by weight, expiring after a write, after an access or at a time each entry chooses, loaded at most once per key however many callers ask together.

  private static final Cache<String, Price> PRICES = Cache.<String, Price>builder("prices")
          .maximumSize(10000)
          .expireAfterWriteMillis(60000)
          .build();
  ...
  Price p = PRICES.get(sku, new Cache.Loader<String, Price>() {
      public Price load(String key) throws Exception {
          return priceService.lookup(key);
      }
  });

Loading

get(Object, Loader) answers a live entry, or runs the loader on the calling thread with no lock held. A second caller asking for the same key while that load runs does not load again: it waits for the first one and gets its result -- the value, or the same failure. A loader that fails, or answers null, leaves the cache as it was; nothing is stored, so the next caller loads again. A key invalidated or put(K, V) while its load is running keeps what that call did: the loaded value is handed to the callers that waited for it and is not stored over the newer state.

A loader may use the cache, but not for the key it is loading; that would wait for itself, and is refused with IllegalStateException.

A waiting virtual thread naps rather than blocking its host, so a slow load holds back only the requests that want its key.

Eviction and expiry

Above the size or weight bound the least recently used entries go first. An expired entry is never answered; it is removed, with an EXPIRED notification, when a read finds it, when a write's periodic sweep does, or on cleanUp(). size() cleans up first, so it counts only live entries.

Removal notifications

The Cache.RemovalListener runs on the thread whose call removed the entry, after the cache's lock is released, so it may use the cache. One that throws is reported on standard error and does not affect the cache or the call that triggered it. Notifications from one call are delivered in the order the entries were removed.

Metrics

Every cache records cache.<name>.hits, .misses, .loads, .load_failures and .evictions (counters), .size and .weight (gauges) and .load.duration (a histogram, milliseconds) in Metrics; the same figures are on the cache's own accessors. Two caches built with one name share the counters, and the gauges read the newer.

Scope and cost

A cache lives in this process only: two instances of a server each hold their own, and nothing is shared or invalidated between them. Values are held by reference, so a value a caller changes changes for every reader. Each entry costs about a hundred bytes beyond its key and value -- a hash map entry with its access-order links, and a node holding the value, its weight and three timestamps -- on the JVM and in the native binary alike.

Server code: this class is not available in the app.

  • Field Details

  • Method Details

    • builder

      public static <K,V> Cache.Builder<K,V> builder(String name)
      A cache named name; the name prefixes its metrics.
    • getName

      public String getName()
    • getIfPresent

      public V getIfPresent(K key)
      The live value for key, or null. Counts a hit or a miss.
    • get

      public V get(K key, Cache.Loader<K,V> loader)
      The live value for key, loading it with loader when absent. See the class description for concurrent callers, failures and null.
    • put

      public void put(K key, V value)
      Stores value, replacing what is there.
    • invalidate

      public void invalidate(K key)
      Removes key, and keeps a load of it already running from storing its result.
    • invalidateAll

      public void invalidateAll()
      Removes every entry, as invalidate(K) does each.
    • cleanUp

      public void cleanUp()
      Removes every expired entry now.
    • size

      public long size()
      Live entries, after a cleanUp().
    • weight

      public long weight()
      The total weight of the entries: their count when no weigher is set.
    • hitCount

      public long hitCount()
    • missCount

      public long missCount()
    • loadCount

      public long loadCount()
      Loads that completed, with a value or with null.
    • loadFailureCount

      public long loadFailureCount()
    • evictionCount

      public long evictionCount()
      Entries evicted for size or weight; expiry and invalidation not counted.