Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

least blocking java cache

Suppose we want to implement a cache for a particular entity.

class Cache {
    private static Map<String, Object> cache = new HashMap<>();

    public static Object get(String id) {
        assert notNullOrEmpty(id);
        return cache.get(id);
    }

    public static Object add(String id, Object element) {
        assert notNullOrEmpty(id) && notNull(element);

        if(cache.containsKey(id)) return cache.get(id);

        cache.put(id, element);
        return element;
    }
}

now we want to ensure this is threadsafe and most importantly optimal when it comes to data access and performance (we dont want to block when its not necessary). For example if we mark both methods as synchronized we will uslessly block two concurrent get() calls which could perfectly work without block.

so we want to block get() only if add() is in process, and block add only if at least one get() or an add() is in process. Multiple concurrent get() executions should not block each other...

How do we do this?


UPDATE

In fact this is not a cache but just a use case i've come up with to describe the problem, the actual purpose is to create a singletone instances store...

For example there is a Currency type which is only instantiated trough its builder and is immutable, builder itself after verifying that parameters passed in are valid checks this so called global cache in static context to see if there is an instance already created... well you got me...

This is not an enum usecase because system will dynamically add new Currency, Market or even Exchange instances which all should be loosely coupled and instantiated only once... (also to prevent heavy GC)

So to clarify the question... think of the global problem of concurrency not the particular examlpe.

I've found this link quite helpful http://tutorials.jenkov.com/java-concurrency/read-write-locks.html

i guess there are some lock types already in JDK for this purpose, but not sure yet.

like image 847
vach Avatar asked May 02 '26 05:05

vach


1 Answers

Actually I gave a talk on this just today at the FOSDEM conference in Burssels. See the slides here: http://www.slideshare.net/cruftex/cache2k-java-caching-turbo-charged-fosdem-2015

Basically you can use Google Guava, however, since Guava is a cache which uses LRU, there is still a synchronized block needed. Something which I am exploring in cache2k is used an advanced eviction algorithm, that needs no list manipulation for the cache access, so locks whatsoever at all.

cache2k is on maven central, add cache2k-api and cache2k-core as dependency and initialize the cache with:

cache = 
  CacheBuilder.newCache(String.class, Object.class)
    .implementation(ClockProPlusCache.class)
    .build();

If you have only cache hits, cache2k is about 5x faster then Guava and 10x faster then EHCache. For your usage pattern e.g. with the Currency type you can run the cache in read through configuration and add a cache source which is responsible for constructing the Currency instances.

So, you don't necessarily do look out for a cache. For the currency example you don't need a cache, since there is a limited space of currency instances. If you want to do the same with a possible non limited space, the cache is the more universal solution, since you have to limit the resource consumption. One example I explored, is using this for formatted dates. See: https://github.com/headissue/cache2k-benchmark/blob/master/zoo/src/test/java/org/cache2k/benchmark/DateFormattingBenchmark.java

For general questions on cache2k, feel free to post them on stack overflow.

like image 127
cruftex Avatar answered May 04 '26 19:05

cruftex