Java time-based map/cache with expiring keys [closed]
Yes. Google Collections, or Guava as it is named now has something called MapMaker which can do exactly that.
ConcurrentMap<Key, Graph> graphs = new MapMaker() .concurrencyLevel(4) .softKeys() .weakValues() .maximumSize(10000) .expiration(10, TimeUnit.MINUTES) .makeComputingMap( new Function<Key, Graph>() { public Graph apply(Key key) { return createExpensiveGraph(key); } });
Update:
As of guava 10.0 (released September 28, 2011) many of these MapMaker methods have been deprecated in favour of the new CacheBuilder:
LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder() .maximumSize(10000) .expireAfterWrite(10, TimeUnit.MINUTES) .build( new CacheLoader<Key, Graph>() { public Graph load(Key key) throws AnyException { return createExpensiveGraph(key); } });
This is a sample implementation that i did for the same requirement and concurrency works well. Might be useful for someone.
import java.text.SimpleDateFormat;import java.util.Date;import java.util.Map;import java.util.concurrent.ConcurrentHashMap;/** * * @author Vivekananthan M * * @param <K> * @param <V> */public class WeakConcurrentHashMap<K, V> extends ConcurrentHashMap<K, V> { private static final long serialVersionUID = 1L; private Map<K, Long> timeMap = new ConcurrentHashMap<K, Long>(); private long expiryInMillis = 1000; private static final SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss:SSS"); public WeakConcurrentHashMap() { initialize(); } public WeakConcurrentHashMap(long expiryInMillis) { this.expiryInMillis = expiryInMillis; initialize(); } void initialize() { new CleanerThread().start(); } @Override public V put(K key, V value) { Date date = new Date(); timeMap.put(key, date.getTime()); System.out.println("Inserting : " + sdf.format(date) + " : " + key + " : " + value); V returnVal = super.put(key, value); return returnVal; } @Override public void putAll(Map<? extends K, ? extends V> m) { for (K key : m.keySet()) { put(key, m.get(key)); } } @Override public V putIfAbsent(K key, V value) { if (!containsKey(key)) return put(key, value); else return get(key); } class CleanerThread extends Thread { @Override public void run() { System.out.println("Initiating Cleaner Thread.."); while (true) { cleanMap(); try { Thread.sleep(expiryInMillis / 2); } catch (InterruptedException e) { e.printStackTrace(); } } } private void cleanMap() { long currentTime = new Date().getTime(); for (K key : timeMap.keySet()) { if (currentTime > (timeMap.get(key) + expiryInMillis)) { V value = remove(key); timeMap.remove(key); System.out.println("Removing : " + sdf.format(new Date()) + " : " + key + " : " + value); } } } }}
Git Repo Link (With Listener Implementation)
https://github.com/vivekjustthink/WeakConcurrentHashMap
Cheers!!
Apache Commons has decorator for Map to expire entries: PassiveExpiringMapIt's more simple than caches from Guava.
P.S. be careful, it's not synchronized.