org.geotoolkit.util.collection
Class Cache<K,V>

Object
  extended by AbstractMap<K,V>
      extended by Cache<K,V>
Type Parameters:
K - The type of key objects.
V - The type of value objects.
All Implemented Interfaces:
Map<K,V>

@ThreadSafe
public class Cache<K,V>
extends AbstractMap<K,V>

A concurrent cache mechanism. This implementation is thread-safe and supports concurrency. A cache entry can be locked when an object is in process of being created. The steps are as below:

  1. Check if the value is already available in the map. If it is, return it immediately and we are done.
  2. Otherwise, get a lock and check again if the value is already available in the map (because the value could have been computed by an other thread between step 1 and the obtention of the lock). If it is, release the lock and we are done.
  3. Otherwise compute the value, store the result and release the lock.

The easiest way (except for exception handling) to use this class is to prepare a Callable statement to be executed only if the object is not in the cache, and to invoke the getOrCreate method. Example:

private final Cache<String,MyObject> cache = new Cache<String,MyObject>();

public MyObject getMyObject(final String key) throws MyCheckedException {
    try {
        return cache.getOrCreate(key, new Callable<MyObject>() {
            MyObject call() throws FactoryException {
                return createMyObject(key);
            }
        });
    } catch (MyCheckedException e) {
        throw e;
    } catch (RuntimeException e) {
        throw e;
    } catch (Exception e) {
        throw new UndeclaredThrowableException(e);
    }
}
An alternative is to perform explicitly all the steps enumerated above. This alternative avoid the creation of a temporary Callable statement which may never be executed, and avoid the exception handling due to the throws Exception clause. Note that the call to putAndUnlock must be in the finally block of a try block beginning immediately after the call to lock, no matter what the result of the computation is (including null).
private final Cache<String,MyObject> cache = new Cache<String,MyObject>();

public MyObject getMyObject(final String key) throws MyCheckedException {
    MyObject value = cache.peek(key);
    if (value == null) {
        final Cache.Handler<MyObject> handler = cache.lock(key);
        try {
            value = handler.peek();
            if (value == null) {
                value = createMyObject(key);
            }
        } finally {
            handler.putAndUnlock(value);
        }
    }
    return value;
}


Eviction of eldest values

The total cost is given at construction time. If the cost(V) method has not been overridden, then the total cost is the maximal amount of values to keep by strong references.


Circular dependencies
This implementation assumes that there is no circular dependencies (or cyclic graph) between the values in the cache. For example if creating A implies creating B, then creating B is not allowed to implies (directly or indirectly) the creation of A. If this rule is not meet, deadlock may occur randomly.

Since:
3.00
Version:
3.19
Author:
Martin Desruisseaux (Geomatys)
Module:
utility/geotk-utility (download)    View source code for this class

Nested Class Summary
static interface Cache.Handler<V>
          The handler returned by lock(K), to be used for unlocking and storing the result.
 
Nested classes/interfaces inherited from class AbstractMap
AbstractMap.SimpleEntry<K,V>, AbstractMap.SimpleImmutableEntry<K,V>
 
Nested classes/interfaces inherited from interface Map
Map.Entry<K,V>
 
Constructor Summary
Cache()
          Creates a new cache with a default initial capacity and cost limit of 100.
Cache(int initialCapacity, long costLimit, boolean soft)
          Creates a new cache using the given initial capacity and cost limit.
 
Method Summary
 void clear()
          Clears the content of this cache.
 boolean containsKey(Object key)
          Returns true if this map contains the specified key.
protected  int cost(V value)
          Computes an estimation of the cost of the given value.
 Set<Map.Entry<K,V>> entrySet()
          Returns the set of entries in this cache.
 V get(Object key)
          Returns the value associated to the given key in the cache.
 V getOrCreate(K key, Callable<? extends V> creator)
          Returns the value for the given key.
 boolean isEmpty()
          Returns true if this cache is empty.
 boolean isKeyCollisionAllowed()
          Returns true if different values may be assigned to the same key.
 Set<K> keySet()
          Returns the set of keys in this cache.
 Cache.Handler<V> lock(K key)
          Gets a lock for the entry at the given key and returns a handler to be used by the caller for unlocking and storing the result.
 V peek(K key)
          If a value is already cached for the given key, returns it.
 V put(K key, V value)
          Puts the given value in cache.
 V remove(Object key)
          Removes the value associated to the given key in the cache.
 void setKeyCollisionAllowed(boolean allowed)
          If set to true, different values may be assigned to the same key.
 int size()
          Returns the number of elements in this cache.
 
Methods inherited from class AbstractMap
clone, containsValue, equals, hashCode, putAll, toString, values
 
Methods inherited from class Object
finalize, getClass, notify, notifyAll, wait, wait, wait
 

Constructor Detail

Cache

public Cache()
Creates a new cache with a default initial capacity and cost limit of 100. The oldest objects will be hold by weak references.


Cache

public Cache(int initialCapacity,
             long costLimit,
             boolean soft)
Creates a new cache using the given initial capacity and cost limit. The initial capacity is the expected number of values to be stored in this cache. More values are allowed, but a little bit of CPU time may be saved if the expected capacity is known before the cache is created.

The cost limit is the maximal value of the total cost (the sum of the cost of all values) before to replace eldest strong references by weak or soft references.

Parameters:
initialCapacity - the initial capacity.
costLimit - The maximum number of objects to keep by strong reference.
soft - If true, use SoftReference instead of WeakReference.
Method Detail

clear

public void clear()
Clears the content of this cache.

Specified by:
clear in interface Map<K,V>
Overrides:
clear in class AbstractMap<K,V>

isEmpty

public boolean isEmpty()
Returns true if this cache is empty.

Specified by:
isEmpty in interface Map<K,V>
Overrides:
isEmpty in class AbstractMap<K,V>
Returns:
true if this cache do not contains any element.

size

public int size()
Returns the number of elements in this cache. The count includes values keep by strong, soft or weak references, and the values under computation at the time this method is invoked.

Specified by:
size in interface Map<K,V>
Overrides:
size in class AbstractMap<K,V>
Returns:
The number of elements currently cached.

containsKey

public boolean containsKey(Object key)
Returns true if this map contains the specified key.

Specified by:
containsKey in interface Map<K,V>
Overrides:
containsKey in class AbstractMap<K,V>

put

public V put(K key,
             V value)
Puts the given value in cache.

Specified by:
put in interface Map<K,V>
Overrides:
put in class AbstractMap<K,V>
Parameters:
key - The key for which to set a value.
value - The value to store.
Returns:
The value previously stored at the given key, or null if none.

remove

public V remove(Object key)
Removes the value associated to the given key in the cache.

Specified by:
remove in interface Map<K,V>
Overrides:
remove in class AbstractMap<K,V>
Parameters:
key - The key of the value to removed.
Returns:
The value that were associated to the given key, or null if none.

get

public V get(Object key)
Returns the value associated to the given key in the cache. This method is similar to peek(K) except that it blocks if the value is currently under computation in an other thread.

Specified by:
get in interface Map<K,V>
Overrides:
get in class AbstractMap<K,V>
Parameters:
key - The key of the value to get.
Returns:
The value associated to the given key, or null if none.

getOrCreate

public V getOrCreate(K key,
                     Callable<? extends V> creator)
              throws Exception
Returns the value for the given key. If a value already exists in the cache, then it is returned immediately. Otherwise the creator.call() method is invoked and its result is saved in this cache for future reuse.

Parameters:
key - The key for which to get the cached or created value.
creator - A method for creating a value, to be invoked only if no value are cached for the given key.
Returns:
The value for the given key, which may have been created as a result of this method call.
Throws:
Exception - If an exception occurred during the execution of creator.call().

peek

public V peek(K key)
If a value is already cached for the given key, returns it. Otherwise returns null. This method is similar to get(Object) except that it doesn't block if the value is in process of being computed in an other thread; it returns null in such case.

Parameters:
key - The key for which to get the cached value.
Returns:
The cached value for the given key, or null if there is none.

lock

public Cache.Handler<V> lock(K key)
Gets a lock for the entry at the given key and returns a handler to be used by the caller for unlocking and storing the result. This method must be used together with a putAndUnlock call in trycatch blocks as in the example below:
Cache.Handler handler = cache.lock();
try {
    // Compute the result...
} finally {
    handler.putAndUnlock(result);
}

Parameters:
key - The key for the entry to lock.
Returns:
A handler to use for unlocking and storing the result.

keySet

public Set<K> keySet()
Returns the set of keys in this cache. The returned set is subjects to the same caution than the ones documented in the ConcurrentHashMap.keySet() method.

Specified by:
keySet in interface Map<K,V>
Overrides:
keySet in class AbstractMap<K,V>

entrySet

public Set<Map.Entry<K,V>> entrySet()
Returns the set of entries in this cache. The returned set is subjects to the same caution than the ones documented in the ConcurrentHashMap.entrySet() method, except that it doesn't support removal of elements (including through the Iterator.remove() method call).

Specified by:
entrySet in interface Map<K,V>
Specified by:
entrySet in class AbstractMap<K,V>

isKeyCollisionAllowed

public boolean isKeyCollisionAllowed()
Returns true if different values may be assigned to the same key. The default value is false.

Returns:
true if key collisions are allowed.

setKeyCollisionAllowed

public void setKeyCollisionAllowed(boolean allowed)
If set to true, different values may be assigned to the same key. This is usually an error, so the default Cache behavior is to thrown an IllegalStateException in such cases, typically when Cache.Handler.putAndUnlock(V) is invoked. However in some cases we may want to relax this check. For example the EPSG database sometime assigns the same key to different kind of objects.

If key collisions are allowed, then if two threads invoke lock(K) concurrently for the same key, then the value to be stored in the map will be the one computed by the first thread to get the lock. The value computed by any other concurrent thread will be ignored by this Cache class (however that thread would still return its computed value to its user).

This property can also be set in order to allow some recursivity. If during the creation of an object, the program asks to this Cache for the same object (using the same key), then the default Cache implementation will consider this situation as a key collision unless this property has been set to true.

Parameters:
allowed - true if key collisions should be allowed.

cost

protected int cost(V value)
Computes an estimation of the cost of the given value. The default implementation returns 1 in all cases. Subclasses should override this method if they have some easy way to measure the relative cost of value objects.

Parameters:
value - The object for which to get an estimation of its cost.
Returns:
The estimated cost of the given object.
See Also:
Instrumentation


Copyright © 2009-2012 Geotoolkit.org. All Rights Reserved.