[concurrency-interest] memoizer cache
Bob Lee
crazybob at crazybob.org
Fri Oct 21 12:34:20 EDT 2011
MapMaker is just a few classes if you want to copy it out (MapMaker,
CustomConcurrentHashMap, ComputingConcurrentHashMap, and Function I think).
We used to do that with Guice.
I'm not sure if it supports #4 yet. When an entry expires, all clients
typically wait for the updated value. You could certainly compute a value
and put it in the map though--other clients would still be able to retrieve
the original value during the computation.
Bob
On Fri, Oct 21, 2011 at 7:39 AM, bhm <bheem at sbcglobal.net> wrote:
> I'm trying to build a cache for configuration objects for my projects-
> Requirements:
> 1 only one instance per key should be created, either because its absent
> for a given key or its expired (in that case it will be recreated).
> 2 most common path asking for a value for a key should not block or
> synchronize.
> 3 when a value doesnt exists for a key, one thread should create the
> instance
> of value and put in the cache, other threads asking for same key should
> wait
> till thats complete.
> 4 if a value is expired, one thread should (re)create the instance of
> value
> and other threads asking for same key (when one thread is recreating it)
> should use expired instance of value and should not block.
>
> My code is largely derived from Christian's reply
>
> http://cs.oswego.edu/pipermail/concurrency-interest/2010-November/007469.html
>
> Please comment or suggest on following, Thanks for you help.
>
> final ConcurrentMap<K, Object> store = new ConcurrentHashMap<K,
> Object>();
>
> V get(K key) {
> Object ret = store.get(key);
>
> if (ret == null) {
> CountDownLatch latch = new CountDownLatch(1);
> ret = store.putIfAbsent(key, latch);
> if (null == ret) {
> ret = new Entry<V>(factory.create(key));
> store.replace(key, ret);
> latch.countDown();
> }
> }
>
> if (ret instanceof CountDownLatch) {
> try {((CountDownLatch) ret).await();} // till new value is
> created
> catch (InterruptedException e) {throw new RuntimeException(e);}
> ret = store.get(key); // get new value
> } else {
> Entry<V> entry = (Entry<V>) ret;
>
> if (evictionpolicy != null && evictionpolicy.isExpired(entry.v))
> {
> final AtomicInteger sync = entry.sync;
>
> if (sync.compareAndSet(0, 1)) { // otherwise retrun old
> value
> try {
> entry = (Entry<V>) store.get(key); // get again
> if (evictionpolicy.isExpired(entry.v)) { //
> double-check
> Entry<V> newval = new
> Entry<V>(factory.create(key));
> store.replace(key, newval);
> ret = newval;
> }
> }
> catch (Throwable catchall) {
> catchall.printStackTrace(System.err);//return old
> value
> }
> finally {sync.set(0);/*unlock*/}
> }
> }
> }
>
> return ((Entry<V>) ret).v;
> }
>
> class Entry<V> {
> final AtomicInteger sync = new AtomicInteger(0);
> final V v;
> Entry(V v) {this.v=v;}
> }
>
>
> form other discussions about similar topics in the list, I understand there
> are
> libraries to do that (MapMaker etc.), I wanted something specific, small,
> just
> to slove the given problem and avoid generalization.
> I couldnt get jcp's Memoizer to work when cache entries could expire. Its
> good
> for lazy one time load.
>
> Thanks again.
> _______________________________________________
> Concurrency-interest mailing list
> Concurrency-interest at cs.oswego.edu
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20111021/3d1ed454/attachment-0001.html>
More information about the Concurrency-interest
mailing list