Oh, it seems I overlooked the requirement to not block other threads when a value is being re-created.<br><br><div class="gmail_quote">On Fri, Oct 21, 2011 at 18:11, Christian Vest Hansen <span dir="ltr"><<a href="mailto:karmazilla@gmail.com">karmazilla@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;"><div><br></div>One thing that comes to mind is this:<div>If you determine that the value you are about to return has expired, then you could replace(key, entry, null) and recursively call get(key) again. If the replace() call returns `false` then someone got ahead of you and already put a null or a new CountDownLatch in there, and the get() call will deal with it. Otherwise it will look, to the following get() call, as if the entry never existed and get() will create it for you. So you don't really need to check the return value of replace() with this approach.</div>

<div>If you do it this way then I guess you don't need the Entry class either. As far as my quick glancing can tell.<div><div></div><div class="h5"><br><br><div class="gmail_quote">On Fri, Oct 21, 2011 at 16:39, bhm <span dir="ltr"><<a href="mailto:bheem@sbcglobal.net" target="_blank">bheem@sbcglobal.net</a>></span> wrote:<br>

<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">I'm trying to build a cache for configuration objects for my projects-<br>
Requirements:<br>
 1 only one instance per key should be created, either because its absent<br>
   for a given key or its expired (in that case it will be recreated).<br>
 2 most common path asking for a value for a key should not block or<br>
synchronize.<br>
 3 when a value doesnt exists for a key, one thread should create the instance<br>
   of value and put in the cache, other threads asking for same key should wait<br>
   till thats complete.<br>
 4 if a value is expired, one thread should (re)create the instance of value<br>
   and other threads asking for same key (when one thread is recreating it)<br>
   should use expired instance of value and should not block.<br>
<br>
My code is largely derived from Christian's reply<br>
<a href="http://cs.oswego.edu/pipermail/concurrency-interest/2010-November/007469.html" target="_blank">http://cs.oswego.edu/pipermail/concurrency-interest/2010-November/007469.html</a><br>
<br>
Please comment or suggest on following, Thanks for you help.<br>
<br>
    final ConcurrentMap<K, Object> store = new ConcurrentHashMap<K, Object>();<br>
<br>
    V get(K key) {<br>
        Object ret = store.get(key);<br>
<br>
        if (ret == null) {<br>
            CountDownLatch latch = new CountDownLatch(1);<br>
            ret = store.putIfAbsent(key, latch);<br>
            if (null == ret) {<br>
                ret = new Entry<V>(factory.create(key));<br>
                store.replace(key, ret);<br>
                latch.countDown();<br>
            }<br>
        }<br>
<br>
        if (ret instanceof CountDownLatch) {<br>
            try {((CountDownLatch) ret).await();} // till new value is created<br>
            catch (InterruptedException e) {throw new RuntimeException(e);}<br>
            ret = store.get(key); // get new value<br>
        } else {<br>
            Entry<V> entry = (Entry<V>) ret;<br>
<br>
            if (evictionpolicy != null && evictionpolicy.isExpired(entry.v)) {<br>
                final AtomicInteger sync = entry.sync;<br>
<br>
                if (sync.compareAndSet(0, 1)) { // otherwise retrun old value<br>
                    try {<br>
                        entry = (Entry<V>) store.get(key); // get again<br>
                        if (evictionpolicy.isExpired(entry.v)) { // double-check<br>
                            Entry<V> newval = new Entry<V>(factory.create(key));<br>
                            store.replace(key, newval);<br>
                            ret = newval;<br>
                        }<br>
                    }<br>
                    catch (Throwable catchall) {<br>
                      catchall.printStackTrace(System.err);//return old value<br>
                    }<br>
                    finally {sync.set(0);/*unlock*/}<br>
                }<br>
            }<br>
        }<br>
<br>
        return ((Entry<V>) ret).v;<br>
    }<br>
<br>
    class Entry<V> {<br>
        final AtomicInteger sync = new AtomicInteger(0);<br>
        final V v;<br>
        Entry(V v) {this.v=v;}<br>
    }<br>
<br>
<br>
form other discussions about similar topics in the list, I understand there are<br>
libraries to do that (MapMaker etc.), I wanted something specific, small, just<br>
to slove the given problem and avoid generalization.<br>
I couldnt get jcp's Memoizer to work when cache entries could expire. Its good<br>
for lazy one time load.<br>
<br>
Thanks again.<br>
_______________________________________________<br>
Concurrency-interest mailing list<br>
<a href="mailto:Concurrency-interest@cs.oswego.edu" target="_blank">Concurrency-interest@cs.oswego.edu</a><br>
<a href="http://cs.oswego.edu/mailman/listinfo/concurrency-interest" target="_blank">http://cs.oswego.edu/mailman/listinfo/concurrency-interest</a><br>
</blockquote></div><br><br clear="all"><div><br></div></div></div><font color="#888888">-- <br>Venlig hilsen / Kind regards,<br>Christian Vest Hansen.<br>
</font></div>
</blockquote></div><br><br clear="all"><div><br></div>-- <br>Venlig hilsen / Kind regards,<br>Christian Vest Hansen.<br>