@SuppressWarnings({ "unchecked", "rawtypes" })
    public static <K, V> V getValue(ConcurrentMap<K, CacheEntry<V>> map, K key, long timeoutMillis, Callable<V> updater, Callable<? extends CacheEntry> cacheEntryFactory, boolean returnExpiredWhileUpdating, Object cacheRequestObject) {
        CacheEntry<V> cacheEntry = map.get(key);
        if(cacheEntry==null) {
            try {
                cacheEntry = cacheEntryFactory.call();
            }
            catch (Exception e) {
                throw new UpdateException(e);
            }
            CacheEntry<V> previousEntry = map.putIfAbsent(key, cacheEntry);
            if(previousEntry != null) {
                cacheEntry = previousEntry;
            }
        }
        try {
            return cacheEntry.getValue(timeoutMillis, updater, returnExpiredWhileUpdating, cacheRequestObject);
        }
        catch (UpdateException e) {
            e.rethrowRuntimeException();
            // make compiler happy
            return null;
        }
    }
@ SuppressWarnings ( { "unchecked" , "rawtypes" } ) public static < K , V > V getValue ( ConcurrentMap < K , CacheEntry < V > > map , K key , long timeoutMillis , Callable < V > updater , Callable < ? extends CacheEntry > cacheEntryFactory , boolean returnExpiredWhileUpdating , Object cacheRequestObject ) { CacheEntry < V > cacheEntry = map . get ( key ) ; if ( cacheEntry == null ) { try { cacheEntry = cacheEntryFactory . call ( ) ; } catch ( Exception e ) { throw new UpdateException ( e ) ; } CacheEntry < V > previousEntry = map . putIfAbsent ( key , cacheEntry ) ; if ( previousEntry != null ) { cacheEntry = previousEntry ; } } try { return cacheEntry . getValue ( timeoutMillis , updater , returnExpiredWhileUpdating , cacheRequestObject ) ; } catch ( UpdateException e ) { e . rethrowRuntimeException ( ) ; return null ; } }
Gets a value from cache. If the key doesn't exist, it will create the value using the updater callback
Prevents cache storms with a lock

The key is always added to the cache. Null return values will also be cached.
You can use this together with ConcurrentLinkedHashMap to create a bounded LRU cache

@param map the cache map
@param key the key to look up
@param timeoutMillis cache entry timeout
@param updater callback to create/update value
@param cacheEntryClass CacheEntry implementation class to use
@param returnExpiredWhileUpdating when true, return expired value while updating new value
@param cacheRequestObject context object that gets passed to hasExpired, shouldUpdate and updateValue methods, not used in default implementation
@return