Correct usage for using loading cache with a ?

Tags: ,



I have a cache of String, Boolean.:

Cache<String, Boolean> myCache = CacheBuilder.newBuilder().build();

My usage pattern is:

if (myCache.get("some-key") == null)  {
     // "some-key" not in cache, do stuff, then insert it
     myCache.put("some-key", Boolean.TRUE);
} 
else {
    // "some-key" already in cache
}

I am trying to change this so that it uses the alternative get method that takes a loader function get(K key, Callable<? extends V> loader), to avoid the possibility that two threads both call myCache.get("some-key") == null and both enter the if block.

I am not sure if below is the correct way to do this?

I think myCache.get("some-key", myCacheLoader) will insert some-key into the cache if it is not present, but I also need to know if it was present or not, so I don’t think the code below is correct.

CacheLoader<String, Boolean> myCacheLoader = createMyCacheLoader();
Cache<String, Boolean> myCache = CacheBuilder.newBuilder().build();

private static CacheLoader<String, Boolean> createMyCacheLoader(){
    return new CacheLoader<String, Boolean>(){
        @Override
        public Boolean load(final String key){
            return Boolean.TRUE;
        }
    };
}

if (!myCache.get("some-key", myCacheLoader))  { // I don't think this can ever be false?
    // I don't think if block will ever be entered?
    // How can I find out if an item isn't in the cache when using a loading cache?
} 
else {
    // "some-key" already in cache 
}

Answer

Build LoadingCache instead of Cache with the CacheLoader to achieve what you want. Please refer to Guava CachesExplained wiki page, specifically:

A LoadingCache is a Cache built with an attached CacheLoader. (…) The canonical way to query a LoadingCache is with the method get(K). This will either return an already cached value, or else use the cache’s CacheLoader to atomically load a new value into the cache.

In your case:

    CacheLoader<String, Boolean> myCacheLoader = CacheLoader.from(key -> Boolean.TRUE);
    LoadingCache<String, Boolean> myCache = CacheBuilder.newBuilder()
            // optional config for LoadingCache
            .build(myCacheLoader);

    // or even inlined:
    LoadingCache<String, Boolean> myCache = CacheBuilder.newBuilder()
            // optional config for LoadingCache
            .build(CacheLoader.from(key -> Boolean.TRUE));

    try {
        final Boolean isValuePresent = myCache.get("some-key");
    } catch (ExecutionException e) {
        throw new UncheckedExecutionException(e.getCause()); // or whatever
    }

    final Boolean isAnotherValuePresent = myCache.getUnchecked("some-key-as-well");


Source: stackoverflow