Created
May 18, 2017 09:10
-
-
Save HussainDerry/c4c9855d625b858a551d75135c23d340 to your computer and use it in GitHub Desktop.
Cache implementation with a periodic memory clean up process
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import java.util.*; | |
| import java.util.concurrent.ConcurrentHashMap; | |
| /** | |
| * Cache implementation with a periodic memory clean up process. | |
| * @author Hussain Al-Derry <[email protected]> | |
| * @version 1.0 | |
| */ | |
| public class ConcurrentCache<K, V> { | |
| private final Map<K, Holder<V>> mMap; | |
| private final long timeToLive; | |
| private final long cleanUpInterval; | |
| private final TimerTask cleanUpTask = new TimerTask() { | |
| @Override | |
| public void run() { | |
| long now = System.currentTimeMillis(); | |
| if(!mMap.isEmpty()){ | |
| Iterator<Map.Entry<K, Holder<V>>> mIterator = mMap.entrySet().iterator(); | |
| while(mIterator.hasNext()){ | |
| long expiry = timeToLive + mIterator.next().getValue().lastAccessed; | |
| if(now > expiry){ | |
| mIterator.remove(); | |
| } | |
| } | |
| } | |
| } | |
| }; | |
| /** | |
| * @param elementTimeToLiveMillis The time (in milliseconds) each element stays alive after it was last accessed. | |
| * @param cleanUpIntervalMillis The interval (in milliseconds) between cache clean ups. | |
| * @param cacheSize The size of the cache. | |
| * */ | |
| public ConcurrentCache(long elementTimeToLiveMillis, long cleanUpIntervalMillis, int cacheSize){ | |
| mMap = new ConcurrentHashMap<>(cacheSize); | |
| this.timeToLive = elementTimeToLiveMillis; | |
| this.cleanUpInterval = cleanUpIntervalMillis; | |
| setupCleanUpProcess(); | |
| } | |
| /** | |
| * Puts the specified value in the cache, overwrites any value previously mapped to the specified key. | |
| * @param key The key which the specified value is associated with. | |
| * @param value The value to be cached. | |
| * */ | |
| public void put(K key, V value){ | |
| mMap.put(key, new Holder<>(value)); | |
| } | |
| /** | |
| * Puts the specified value in the cache, if a value is already mapped to the specified key that value is returned. | |
| * @param key The key which the specified value is associated with. | |
| * @param value The value to be cached. | |
| * */ | |
| public V putIfAbsent(K key, V value){ | |
| return mMap.putIfAbsent(key, new Holder<>(value)).getValue(); | |
| } | |
| /** | |
| * Returns the value associated with the specified key, if no mapping is found the method returns null. | |
| * @param key The key associated with the value to be returned. | |
| * */ | |
| public V get(K key){ | |
| Holder<V> mHolder = mMap.get(key); | |
| if(mHolder != null){ | |
| return mHolder.getValue(); | |
| }else{ | |
| return null; | |
| } | |
| } | |
| /** | |
| * Returns true if the Cache has a value associated with the specified key, else returns false; | |
| * @param key The key to be checked | |
| * @return true if the cache has a value mapped to the given key. | |
| * */ | |
| public boolean containsKey(K key){ | |
| return mMap.containsKey(key); | |
| } | |
| /** | |
| * Removes the value associated with the specified key. | |
| * @param key The key associated with the value to be removed. | |
| * @return | |
| * */ | |
| public V remove(K key){ | |
| Holder<V> mHolder = mMap.remove(key); | |
| if(mHolder != null){ | |
| return mHolder.getValue(); | |
| }else{ | |
| return null; | |
| } | |
| } | |
| /** | |
| * Creates a daemon thread to take care of the clean up process | |
| * */ | |
| private void setupCleanUpProcess(){ | |
| new Timer(true).scheduleAtFixedRate(cleanUpTask, cleanUpInterval, cleanUpInterval); | |
| } | |
| /** | |
| * Holder class for cache entries to monitor access to the entry. | |
| * */ | |
| private class Holder<T>{ | |
| long lastAccessed; | |
| T value; | |
| Holder(T value){ | |
| lastAccessed = System.currentTimeMillis(); | |
| this.value = value; | |
| } | |
| T getValue(){ | |
| lastAccessed = System.currentTimeMillis(); | |
| return this.value; | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment