0

I need to fetch some string resources from Amazon S3 in a concurrent multithreaded environment. I would like to implement caching using Amazon ElastiCache. In essence I would like to implement a method like that:

String getSomething(key) {
    String something = elastiCache.get(key);
    if (something == null) {
        something = s3.get(key);
        elastiCache.put(key, something);
    }
    return something;
}

The problem is that in concurrent environment the code like this is a subject to race conditions. If the key expires in elastiCache, multiple threads will try to fetch it from s3 and put it back to elastiCache. The easiest way to avoid it is to put synchronized on the method. This is not optimal, because all calls to getSomething will be interleaving and that will result in a slowdown for the case when the value is in elastiCache. I found CAS methods on MemcachedClient: gets/asyncGets and as/asyncCAS. Using this methods I can make it so that only the thread that didn't find the key in elastiCache will put it back. But is there a way I could avoid accessing s3 from multiple threads, short of using synchronized?

Leon
  • 41
  • 4

1 Answers1

0

What about a double-checked lock? Like this:

String getSomething(key) {
    String something = elastiCache.get(key);
    if (something == null) {
        synchronized(this) {
            something = elastiCache.get(key);
            if (something == null) {
                something = s3.get(key);
                elastiCache.put(key, something);
            }
        }
    }
    return something;
}
MatteoSp
  • 2,940
  • 5
  • 28
  • 36
  • That's genius! Works very well. I should have came up with this myself. Somehow I decided that Amazon APIs should have a built in support for this... I need to remind myself to think of a simple solution first before going into complications. – Leon May 26 '15 at 19:31