Java基于时间的地图/caching与过期的关键

是否有人知道Java Map或类似的标准数据存储,在给定的超时后自动清除条目? 这意味着老化,旧的过期条目自动老化。

最好在通过Maven访问的开源库中?

我知道自己实现这些function的方法,并且在过去已经做了好几次,所以我并不是要求这方面的build议,而是指向一个很好的参考实现。

像WeakHashMap这样的基于WeakReference的解决scheme不是一种select,因为我的密钥可能是非干扰string,我想要一个不依赖于垃圾收集器的可configuration超时。

Ehcache也是我不想依赖的选项,因为它需要外部configuration文件。 我正在寻找一个只有代码的解决scheme。

是。 谷歌collections集,或现在命名的番石榴现在有一种叫做MapMaker ,可以做到这一点。

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); } }); 

更新:

从番石榴10.0(2011年9月28日发布)开始,许多MapMaker方法已被弃用,以支持新的CacheBuilder :

 LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder() .concurrencyLevel(4) .weakKeys() .maximumSize(10000) .expireAfterWrite(10, TimeUnit.MINUTES) .build( new CacheLoader<Key, Graph>() { public Graph load(Key key) throws AnyException { return createExpensiveGraph(key); } }); 

ExpiringMap具有与Google Guava类似的function。

 Map<String, Connection> map = ExpiringMap.builder() .expiration(30, TimeUnit.SECONDS) .build(); 

你可以尝试一下我自己实现的一个自动到期的哈希映射。 此实现不使用线程来删除过期的条目,而是使用DelayQueue ,该操作会在每个操作中自动清除。

这是我为相同的要求做的示例实现,并发性很好。 可能对某人有用。

 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); } } } } } 

干杯!!

Apache Commons的地图装饰器过期实体: PassiveExpiringMap它比Guava的caching更简单。

PS要小心,它不是同步的。

Google集合(番石榴)有MapMaker ,您可以在其中设置时间限制(过期),并且您可以使用软参考或弱参考使用工厂方法来创build您select的实例。

听起来像ehcache是​​为你想要的矫枉过正,但是请注意,它不需要外部configuration文件。

将configuration移动到声明性configuration文件中通常是一个好主意(因此,当新安装需要不同的到期时间时,您不需要重新编译),但是完全不需要,您仍然可以通过编程来configuration它。 http://www.ehcache.org/documentation/user-guide/configuration

番石榴caching很容易实现。我们可以使用番石榴caching在时间基础上过期的关键。 我已阅读完整的文章和下面给我的学习的关键。

 cache = CacheBuilder.newBuilder().refreshAfterWrite(2,TimeUnit.SECONDS). build(new CacheLoader<String, String>(){ @Override public String load(String arg0) throws Exception { // TODO Auto-generated method stub return addcache(arg0); } } 

参考: 番石榴caching的例子

如果有人需要一个简单的东西,以下是一个简单的关键到期集。 它可能很容易转换成地图。

 public class CacheSet<K> { public static final int TIME_OUT = 86400 * 1000; LinkedHashMap<K, Hit> linkedHashMap = new LinkedHashMap<K, Hit>() { @Override protected boolean removeEldestEntry(Map.Entry<K, Hit> eldest) { final long time = System.currentTimeMillis(); if( time - eldest.getValue().time > TIME_OUT) { Iterator<Hit> i = values().iterator(); i.next(); do { i.remove(); } while( i.hasNext() && time - i.next().time > TIME_OUT ); } return false; } }; public boolean putIfNotExists(K key) { Hit value = linkedHashMap.get(key); if( value != null ) { return false; } linkedHashMap.put(key, new Hit()); return true; } private static class Hit { final long time; Hit() { this.time = System.currentTimeMillis(); } } } 

通常情况下,caching应该保留一段时间的对象,并在一段时间后暴露他们。 持有对象的好时机取决于用例。 我希望这个东西很简单,没有线程或者调度器。 这种方法适用于我。 与SoftReference不同的是,对象保证可用一些最less的时间。 但是,在太阳变成红色巨人之前,不要留在记忆中。

作为使用示例,考虑一个缓慢响应的系统,它应该能够检查最近是否已经完成请求,并且在这种情况下,即使忙碌的用户多次点击button,也不会执行两次请求的动作。 但是,如果在一段时间之后要求同样的动作,则应该再次执行。

 class Cache<T> { long avg, count, created, max, min; Map<T, Long> map = new HashMap<T, Long>(); /** * @param min minimal time [ns] to hold an object * @param max maximal time [ns] to hold an object */ Cache(long min, long max) { created = System.nanoTime(); this.min = min; this.max = max; avg = (min + max) / 2; } boolean add(T e) { boolean result = map.put(e, Long.valueOf(System.nanoTime())) != null; onAccess(); return result; } boolean contains(Object o) { boolean result = map.containsKey(o); onAccess(); return result; } private void onAccess() { count++; long now = System.nanoTime(); for (Iterator<Entry<T, Long>> it = map.entrySet().iterator(); it.hasNext();) { long t = it.next().getValue(); if (now > t + min && (now > t + max || now + (now - created) / count > t + avg)) { it.remove(); } } } }