|
||||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD | |||||||||
ObjectAbstractMap<K,V>
Cache<K,V>
K - The type of key objects.V - The type of value objects.@ThreadSafe public class Cache<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:
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 cost of a value is the value returned by cost(V). The default
implementation returns 1 in all cases, but subclasses can override this method for
more elaborated cost computation.
The total cost is the sum of the cost of all values held by strong reference in this cache. The total cost does not include the cost of values held by weak or soft reference.
The cost limit is the maximal value allowed for the total cost. If the total cost exceed this value, then strong references to the eldest values are replaced by weak or soft references until the total cost become equals or lower than the cost limit.
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.
| 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 |
|---|
public Cache()
public Cache(int initialCapacity,
long costLimit,
boolean soft)
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.
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 |
|---|
public void clear()
clear in interface Map<K,V>clear in class AbstractMap<K,V>public boolean isEmpty()
true if this cache is empty.
isEmpty in interface Map<K,V>isEmpty in class AbstractMap<K,V>true if this cache do not contains any element.public int size()
size in interface Map<K,V>size in class AbstractMap<K,V>public boolean containsKey(Object key)
true if this map contains the specified key.
containsKey in interface Map<K,V>containsKey in class AbstractMap<K,V>
public V put(K key,
V value)
put in interface Map<K,V>put in class AbstractMap<K,V>key - The key for which to set a value.value - The value to store.
null if none.public V remove(Object key)
remove in interface Map<K,V>remove in class AbstractMap<K,V>key - The key of the value to removed.
null if none.public V get(Object key)
peek(K) except that it blocks if the value is currently under computation in an
other thread.
get in interface Map<K,V>get in class AbstractMap<K,V>key - The key of the value to get.
null if none.
public V getOrCreate(K key,
Callable<? extends V> creator)
throws Exception
creator.call() method is invoked and
its result is saved in this cache for future reuse.
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.
Exception - If an exception occurred during the execution of creator.call().public V peek(K key)
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.
key - The key for which to get the cached value.
null if there is none.public Cache.Handler<V> lock(K key)
putAndUnlock call in try … catch
blocks as in the example below:
Cache.Handler handler = cache.lock();
try {
// Compute the result...
} finally {
handler.putAndUnlock(result);
}
key - The key for the entry to lock.
public Set<K> keySet()
ConcurrentHashMap.keySet() method.
keySet in interface Map<K,V>keySet in class AbstractMap<K,V>public Set<Map.Entry<K,V>> entrySet()
ConcurrentHashMap.entrySet() method, except that
it doesn't support removal of elements (including through the Iterator.remove()
method call).
entrySet in interface Map<K,V>entrySet in class AbstractMap<K,V>public boolean isKeyCollisionAllowed()
true if different values may be assigned to the same key.
The default value is false.
true if key collisions are allowed.public void setKeyCollisionAllowed(boolean allowed)
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.
allowed - true if key collisions should be allowed.protected int cost(V value)
value - The object for which to get an estimation of its cost.
Instrumentation
|
||||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD | |||||||||