Class BlockingCache
- java.lang.Object
-
- net.sf.ehcache.constructs.EhcacheDecoratorAdapter
-
- net.sf.ehcache.constructs.blocking.BlockingCache
-
- All Implemented Interfaces:
java.lang.Cloneable,Ehcache,InternalEhcache
- Direct Known Subclasses:
SelfPopulatingCache
public class BlockingCache extends EhcacheDecoratorAdapter
A blocking decorator for an Ehcache, backed by aEhcache.It allows concurrent read access to elements already in the cache. If the element is null, other reads will block until an element with the same key is put into the cache.
This is useful for constructing read-through or self-populating caches.
This implementation uses the
ReadWriteLockSyncclass. If you wish to use this class, you will need the concurrent package in your class path.It features:
- Excellent liveness.
- Fine-grained locking on each element, rather than the cache as a whole.
- Scalability to a large number of threads.
"Hashtable / synchronizedMap uses the "one big fat lock" approach to guard the mutable state of the map. That works, but is a big concurrency bottleneck, as you've observed. You went to the opposite extreme, one lock per key. That works (as long as you've got sufficient synchronization in the cache itself to protect its own data structures.)
Lock striping is a middle ground, partitioning keys into a fixed number of subsets, like the trick used at large theaters for will-call ticket pickup -- there are separate lines for "A-F, G-M, N-R, and S-Z". This way, there are a fixed number of locks, each guarding (hopefully) 1/Nth of the keys." - Brian Goetz
Further improvements to hashing suggested by Joe Bowbeer.
- Version:
- $Id$
- Author:
- Greg Luck
-
-
Field Summary
Fields Modifier and Type Field Description protected inttimeoutMillisThe amount of time to block a thread before a LockTimeoutException is thrown-
Fields inherited from class net.sf.ehcache.constructs.EhcacheDecoratorAdapter
underlyingCache
-
-
Constructor Summary
Constructors Constructor Description BlockingCache(Ehcache cache)Creates a BlockingCache which decorates the supplied cache.BlockingCache(Ehcache cache, int numberOfStripes)Creates a BlockingCache which decorates the supplied cache.
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method Description Elementget(java.io.Serializable key)Gets an element from the cache.Elementget(java.lang.Object key)Looks up an entry.java.util.MapgetAllWithLoader(java.util.Collection keys, java.lang.Object loaderArgument)This method is not appropriate to use with BlockingCache.protected EhcachegetCache()Retrieve the EHCache backing cacheprotected SyncgetLockForKey(java.lang.Object key)Gets the Sync to use for a given key.intgetTimeoutMillis()Gets the time to wait to acquire a lock.ElementgetWithLoader(java.lang.Object key, CacheLoader loader, java.lang.Object loaderArgument)This method is not appropriate to use with BlockingCache.java.lang.Stringliveness()Synchronized version of getName to test liveness of the object lock.voidload(java.lang.Object key)This method is not appropriate to use with BlockingCache.voidloadAll(java.util.Collection keys, java.lang.Object argument)This method is not appropriate to use with BlockingCache.voidput(Element element)Adds an entry and unlocks itvoidput(Element element, boolean doNotNotifyCacheReplicators)Put an element in the cache.ElementputIfAbsent(Element element)Put an element in the cache if no element is currently mapped to the elements key.ElementputIfAbsent(Element element, boolean doNotNotifyCacheReplicators)Put an element in the cache if no element is currently mapped to the elements key.voidputQuiet(Element element)Put an element in the cache, without updating statistics, or updating listeners.voidputWithWriter(Element element)Put an element in the cache writing through a CacheWriter.voidregisterCacheLoader(CacheLoader cacheLoader)Register aCacheLoaderwith the cache.voidsetTimeoutMillis(int timeoutMillis)Sets the time to wait to acquire a lock.voidunregisterCacheLoader(CacheLoader cacheLoader)Unregister aCacheLoaderwith the cache.-
Methods inherited from class net.sf.ehcache.constructs.EhcacheDecoratorAdapter
acquireReadLockOnKey, acquireWriteLockOnKey, addPropertyChangeListener, bootstrap, calculateInMemorySize, calculateOffHeapSize, calculateOnDiskSize, clone, createQuery, disableDynamicFeatures, dispose, evictExpiredElements, flush, getAll, getBootstrapCacheLoader, getCacheConfiguration, getCacheEventNotificationService, getCacheExceptionHandler, getCacheManager, getDiskStoreSize, getGuid, getInternalContext, getKeys, getKeysNoDuplicateCheck, getKeysWithExpiryCheck, getMemoryStoreSize, getName, getOffHeapStoreSize, getQuiet, getQuiet, getRegisteredCacheExtensions, getRegisteredCacheLoaders, getRegisteredCacheWriter, getSearchAttribute, getSearchAttributes, getSize, getStatistics, getStatus, getWriterManager, hasAbortedSizeOf, initialise, isClusterBulkLoadEnabled, isClusterCoherent, isDisabled, isElementInMemory, isElementInMemory, isElementOnDisk, isElementOnDisk, isExpired, isKeyInCache, isNodeBulkLoadEnabled, isNodeCoherent, isReadLockedByCurrentThread, isSearchable, isValueInCache, isWriteLockedByCurrentThread, putAll, recalculateSize, registerCacheExtension, registerCacheWriter, registerDynamicAttributesExtractor, releaseReadLockOnKey, releaseWriteLockOnKey, remove, remove, remove, remove, removeAll, removeAll, removeAll, removeAll, removeAndReturnElement, removeElement, removePropertyChangeListener, removeQuiet, removeQuiet, removeWithWriter, replace, replace, setBootstrapCacheLoader, setCacheExceptionHandler, setCacheManager, setDisabled, setName, setNodeBulkLoadEnabled, setNodeCoherent, setTransactionManagerLookup, toString, tryReadLockOnKey, tryWriteLockOnKey, unregisterCacheExtension, unregisterCacheWriter, waitUntilClusterBulkLoadComplete, waitUntilClusterCoherent
-
-
-
-
Constructor Detail
-
BlockingCache
public BlockingCache(Ehcache cache, int numberOfStripes) throws CacheException
Creates a BlockingCache which decorates the supplied cache.- Parameters:
cache- a backing ehcache.numberOfStripes- how many stripes to has the keys against. Must be a non-zero even number. This is a trade-off between memory use and concurrency- Throws:
CacheException- shouldn't happen- Since:
- 1.2
-
BlockingCache
public BlockingCache(Ehcache cache) throws CacheException
Creates a BlockingCache which decorates the supplied cache.- Parameters:
cache- a backing ehcache.- Throws:
CacheException- shouldn't happen- Since:
- 1.6.1
-
-
Method Detail
-
getCache
protected Ehcache getCache()
Retrieve the EHCache backing cache- Returns:
- the backing cache
-
get
public Element get(java.lang.Object key) throws java.lang.RuntimeException, LockTimeoutException
Looks up an entry. Blocks if the entry is null until a call toput(net.sf.ehcache.Element)is done to put an Element in.If a put is not done, the lock is never released.
If this method throws an exception, it is the responsibility of the caller to catch that exception and call
put(new Element(key, null));to release the lock acquired. SeeSelfPopulatingCachefor an example.Note. If a LockTimeoutException is thrown while doing a
getit means the lock was never acquired, therefore it is a threading error to callput(net.sf.ehcache.Element)- Specified by:
getin interfaceEhcache- Overrides:
getin classEhcacheDecoratorAdapter- Parameters:
key- an Object value- Returns:
- the element, or null, if it does not exist.
- Throws:
LockTimeoutException- if timeout millis is non zero and this method has been unable to acquire a lock in that timejava.lang.RuntimeException- if thrown the lock will not released. Catch and callput(new Element(key, null));to release the lock acquired.- See Also:
Ehcache.isExpired(net.sf.ehcache.Element)
-
getLockForKey
protected Sync getLockForKey(java.lang.Object key)
Gets the Sync to use for a given key.- Parameters:
key- the key- Returns:
- one of a limited number of Sync's.
-
put
public void put(Element element)
Adds an entry and unlocks it- Specified by:
putin interfaceEhcache- Overrides:
putin classEhcacheDecoratorAdapter- Parameters:
element- An object. If Serializable it can fully participate in replication and the DiskStore.
-
put
public void put(Element element, boolean doNotNotifyCacheReplicators) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, CacheException
Description copied from class:EhcacheDecoratorAdapterPut an element in the cache.Resets the access statistics on the element, which would be the case if it has previously been gotten from a cache, and is now being put back.
Also notifies the CacheEventListener that:
- the element was put, but only if the Element was actually put.
- if the element exists in the cache, that an update has occurred, even if the element would be expired if it was requested
- Specified by:
putin interfaceEhcache- Overrides:
putin classEhcacheDecoratorAdapter- Parameters:
element- An object. If Serializable it can fully participate in replication and the DiskStore.doNotNotifyCacheReplicators- whether the put is coming from a doNotNotifyCacheReplicators cache peer, in which case this put should not initiate a further notification to doNotNotifyCacheReplicators cache peers- Throws:
java.lang.IllegalArgumentException- if the element is nulljava.lang.IllegalStateException- if the cache is notStatus.STATUS_ALIVECacheException
-
putQuiet
public void putQuiet(Element element) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, CacheException
Description copied from class:EhcacheDecoratorAdapterPut an element in the cache, without updating statistics, or updating listeners. This is meant to be used in conjunction withEhcache.getQuiet(java.io.Serializable)- Specified by:
putQuietin interfaceEhcache- Overrides:
putQuietin classEhcacheDecoratorAdapter- Parameters:
element- An object. If Serializable it can fully participate in replication and the DiskStore.- Throws:
java.lang.IllegalArgumentException- if the element is nulljava.lang.IllegalStateException- if the cache is notStatus.STATUS_ALIVECacheException
-
putWithWriter
public void putWithWriter(Element element) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, CacheException
Description copied from class:EhcacheDecoratorAdapterPut an element in the cache writing through a CacheWriter. If no CacheWriter has been registered for the cache, then this method throws an exception.Resets the access statistics on the element, which would be the case if it has previously been gotten from a cache, and is now being put back.
Also notifies the CacheEventListener, if the writer operation succeeds, that:
- the element was put, but only if the Element was actually put.
- if the element exists in the cache, that an update has occurred, even if the element would be expired if it was requested
- Specified by:
putWithWriterin interfaceEhcache- Overrides:
putWithWriterin classEhcacheDecoratorAdapter- Parameters:
element- An object. If Serializable it can fully participate in replication and the DiskStore.- Throws:
java.lang.IllegalArgumentException- if the element is nulljava.lang.IllegalStateException- if the cache is notStatus.STATUS_ALIVECacheException- if no CacheWriter was registered
-
putIfAbsent
public Element putIfAbsent(Element element) throws java.lang.NullPointerException
Description copied from class:EhcacheDecoratorAdapterPut an element in the cache if no element is currently mapped to the elements key.- Specified by:
putIfAbsentin interfaceEhcache- Overrides:
putIfAbsentin classEhcacheDecoratorAdapter- Parameters:
element- element to be added- Returns:
- the element previously cached for this key, or null if none.
- Throws:
java.lang.NullPointerException- if the element is null, or has a null key
-
putIfAbsent
public Element putIfAbsent(Element element, boolean doNotNotifyCacheReplicators) throws java.lang.NullPointerException
Description copied from interface:EhcachePut an element in the cache if no element is currently mapped to the elements key.- Specified by:
putIfAbsentin interfaceEhcache- Overrides:
putIfAbsentin classEhcacheDecoratorAdapter- Parameters:
element- element to be addeddoNotNotifyCacheReplicators- whether the put is coming from a doNotNotifyCacheReplicators cache peer, in which case this put should not initiate a further notification to doNotNotifyCacheReplicators cache peers- Returns:
- the element previously cached for this key, or null if none.
- Throws:
java.lang.NullPointerException- if the element is null, or has a null key
-
get
public Element get(java.io.Serializable key) throws java.lang.IllegalStateException, CacheException
Gets an element from the cache. Updates Element StatisticsNote that the Element's lastAccessTime is always the time of this get. Use
EhcacheDecoratorAdapter.getQuiet(Object)to peak into the Element to see its last access time with get- Specified by:
getin interfaceEhcache- Overrides:
getin classEhcacheDecoratorAdapter- Parameters:
key- a serializable value- Returns:
- the element, or null, if it does not exist.
- Throws:
java.lang.IllegalStateException- if the cache is notStatus.STATUS_ALIVECacheException- See Also:
EhcacheDecoratorAdapter.isExpired(net.sf.ehcache.Element)
-
liveness
public java.lang.String liveness()
Synchronized version of getName to test liveness of the object lock.The time taken for this method to return is a useful measure of runtime contention on the cache.
- Returns:
- the name of the cache.
-
setTimeoutMillis
public void setTimeoutMillis(int timeoutMillis)
Sets the time to wait to acquire a lock. This may be modified at any time.The consequences of setting a timeout are:
- if a lock cannot be acquired in the given time a LockTimeoutException is thrown.
- if there is a queue of threads waiting for the first thread to complete, but it does not complete within the time out period, the successive threads may find that they have exceeded their lock timeouts and fail. This is usually a good thing because it stops a build up of threads from overwhelming a busy resource, but it does need to be considered in the design of user interfaces. The timeout should be set no greater than the time a user would be expected to wait before considering the action will never return
- it will be common to see a number of threads timeout trying to get the same lock. This is a normal and desired consequence.
- There are no partial failures in the system. But there is a greater possibility that a temporary overload in one part of the system can cause a back up that may take a long time to recover from.
- A failing method that perhaps fails because a resource is overloaded will be hit by each thread in turn, no matter whether there is a still a user who cares about getting a response.
- Parameters:
timeoutMillis- the time in ms. Must be a positive number. 0 means wait forever.
-
getTimeoutMillis
public int getTimeoutMillis()
Gets the time to wait to acquire a lock.- Returns:
- the time in ms.
-
registerCacheLoader
public void registerCacheLoader(CacheLoader cacheLoader)
Register aCacheLoaderwith the cache. It will then be tied into the cache lifecycle.If the CacheLoader is not initialised, initialise it.
- Specified by:
registerCacheLoaderin interfaceEhcache- Overrides:
registerCacheLoaderin classEhcacheDecoratorAdapter- Parameters:
cacheLoader- A Cache Loader to register
-
unregisterCacheLoader
public void unregisterCacheLoader(CacheLoader cacheLoader)
Unregister aCacheLoaderwith the cache. It will then be detached from the cache lifecycle.- Specified by:
unregisterCacheLoaderin interfaceEhcache- Overrides:
unregisterCacheLoaderin classEhcacheDecoratorAdapter- Parameters:
cacheLoader- A Cache Loader to unregister
-
getWithLoader
public Element getWithLoader(java.lang.Object key, CacheLoader loader, java.lang.Object loaderArgument) throws CacheException
This method is not appropriate to use with BlockingCache.- Specified by:
getWithLoaderin interfaceEhcache- Overrides:
getWithLoaderin classEhcacheDecoratorAdapter- Parameters:
key- key whose associated value is to be returned.loader- the override loader to use. If null, the cache's default loader will be usedloaderArgument- an argument to pass to the CacheLoader.- Returns:
- an element if it existed or could be loaded, otherwise null
- Throws:
CacheException- if this method is called
-
getAllWithLoader
public java.util.Map getAllWithLoader(java.util.Collection keys, java.lang.Object loaderArgument) throws CacheExceptionThis method is not appropriate to use with BlockingCache.- Specified by:
getAllWithLoaderin interfaceEhcache- Overrides:
getAllWithLoaderin classEhcacheDecoratorAdapter- Parameters:
keys- a collection of keys to be returned/loadedloaderArgument- an argument to pass to the CacheLoader.- Returns:
- a Map populated from the Cache. If there are no elements, an empty Map is returned.
- Throws:
CacheException- if this method is called
-
load
public void load(java.lang.Object key) throws CacheExceptionThis method is not appropriate to use with BlockingCache.- Specified by:
loadin interfaceEhcache- Overrides:
loadin classEhcacheDecoratorAdapter- Parameters:
key- key whose associated value to be loaded using the associated cacheloader if this cache doesn't contain it.- Throws:
CacheException- if this method is called
-
loadAll
public void loadAll(java.util.Collection keys, java.lang.Object argument) throws CacheExceptionThis method is not appropriate to use with BlockingCache.- Specified by:
loadAllin interfaceEhcache- Overrides:
loadAllin classEhcacheDecoratorAdapter- Parameters:
keys- - collection of the keys whose associated values to be loaded into this cache by using the associated cacheloader if this cache doesn't contain them.argument- can be anything that makes sense to the loaderThe Ehcache native API provides similar functionality to loaders using the decorator
SelfPopulatingCache- Throws:
CacheException- if this method is called
-
-