code: public Optional<V> get(K key) {
      if (cacheIsFull()) {
        Entry entry = mMap.get(key);
        if (entry == null) {
          return load(key);
        }
        return Optional.ofNullable(entry.mValue);
      }
      Entry result = mMap.compute(key, (k, entry) -> {
        if (entry != null) {
          entry.mReferenced = true;
          return entry;
        }
        Optional<V> value = load(key);
        if (value.isPresent()) {
          onCacheUpdate(key, value.get());
          Entry newEntry = new Entry(key, value.get());
          newEntry.mDirty = false;
          return newEntry;
        }
        return null;
      });
      if (result == null || result.mValue == null) {
        return Optional.empty();
      }
      wakeEvictionThreadIfNecessary();
      return Optional.of(result.mValue);
    }
docs: Retrieves a value from the cache, loading it from the backing store if necessary.
  
  If the value needs to be loaded, concurrent calls to get(key) will block while waiting for the
  first call to finish loading the value.
  
  @param key the key to get the value for
  @return the value, or empty if the key doesn't exist in the cache or in the backing store