user5447339
user5447339

Reputation:

How to populate entries into Loading Cache guava?

I have a use case where I want to populate entries into a data structure from multiple threads and after a particular size is reached start dropping old records. So I decided to use Guava Loading Cache for this.

I want to populate entries into my Loading Cache from multiple threads and I am setting eviction based policy as Size Based Eviction.

  private final ScheduledExecutorService executorService = Executors
      .newSingleThreadScheduledExecutor();
  private final LoadingCache<String, DataBuilder> cache =
      CacheBuilder.newBuilder().maximumSize(10000000)
          .removalListener(RemovalListeners.asynchronous(new CustomListener(), executorService))
          .build(new CacheLoader<String, DataBuilder>() {
            @Override
            public DataBuilder load(String key) throws Exception {
              // what I should do here?
              // return 
            }
          });

// this will be called from multiple threads to populate the cache
public void addToCache(String key, DataBuilder dataBuilder) {
    // what I should do here?
    //cache.get(key).
}

My addToCache method will be called from multiple threads to populate the cache. I am confuse what I should be doing inside addToCache method to fill the cache and also what does my load method looks like?

Here DataBuilder is my builder pattern.

Upvotes: 5

Views: 10214

Answers (1)

Nicolas Filotto
Nicolas Filotto

Reputation: 44995

Obviously your problem is that you don't get the main purpose of a CacheLoader.

A CacheLoader is used to automatically load the value of a given key (which doesn't exist in the cache yet) when calling get(K key) or getUnchecked(K key) in way that even if we have several threads trying to get the value of the same key at the same time, only one thread will actually load the value and once done all calling threads will have the same value.

This is typically useful when the value to load takes some time, like for example when it is the result of a database access or a long computation, because the longer it takes the higher is the probability to have several threads trying to load the same value at the same time which would waste resources without a mechanism that ensures that only one thread will load the data for all calling threads.

So here let's say that your DataBuilder's instances are long to build or you simply need to ensure that all threads will have the same instance for a given key, you would then indeed need a CacheLoader and it would look like this:

new CacheLoader<String, DataBuilder>() {
    @Override
    public DataBuilder load(String key) throws Exception {
        return callSomeMethodToBuildItFromTheKey(key); // could be new DataBuilder(key)
    }
}

Thanks to the CacheLoader, you have no need to call put explicitly anymore as your cache will be populated behind the scene by the threads calling cache.get(myKey) or cache.getUnchecked(myKey).

If you want to manually populate your cache, you can simply use the put(K key, V value) method like any Cache as next:

public void addToCache(String key, DataBuilder dataBuilder) {
    cache.put(key, dataBuilder);
}

If you intend to populate the cache yourself, you don't need a CacheLoader, you can simply call build() instead of build(CacheLoader<? super K1,V1> loader) to build your Cache instance (it won't be a LoadingCache anymore).

Your code would then be:

private final Cache<String, DataBuilder> cache =
      CacheBuilder.newBuilder().maximumSize(10000000)
          .removalListener(
              RemovalListeners.asynchronous(new CustomListener(), executorService)
          ).build();

Upvotes: 13

Related Questions