具有过期键的java基于时间的map/cache

zz2j4svz  于 2021-06-30  发布在  Java
关注(0)|答案(10)|浏览(438)

**结束。**此问题不符合堆栈溢出准则。它目前不接受答案。
**想改进这个问题吗?**更新问题,使其成为堆栈溢出的主题。

三年前关门了。
改进这个问题
你们知道javaMap或类似的标准数据存储在给定的超时后自动清除条目吗?这意味着老化,旧的过期条目自动“老化”。
最好是在一个可以通过maven访问的开源库中?
我自己也知道实现这个功能的方法,而且在过去也做过几次,所以我不是在征求这方面的建议,而是寻求一个好的参考实现的指针。
基于weakreference的解决方案(如weakhashmap)不是一个选项,因为我的密钥可能是非interned字符串,我需要一个不依赖于垃圾收集器的可配置超时。
ehcache也是一个我不想依赖的选项,因为它需要外部配置文件。我正在寻找一个代码唯一的解决方案。

rdrgkggo

rdrgkggo1#

对。googlecollections,或者叫guava,现在有一个叫做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);
         }
       });

更新:
从guava 10.0(2011年9月28日发布)起,许多Map制作方法都被弃用,取而代之的是新的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);
          }
        });
camsedfj

camsedfj2#

googlecollections(guava)有一个mapmaker,您可以在其中设置时间限制(过期),并且可以在选择时使用软引用或弱引用,使用工厂方法创建您选择的示例。

zqdjd7g9

zqdjd7g93#

您可以尝试我的自我过期哈希Map的实现。这个实现不使用线程来删除过期的条目,而是使用delayqueue,它在每次操作时自动清理。

wecizke3

wecizke34#

通常,缓存应该将对象保留一段时间,并在一段时间后公开其中的一部分。持有一个对象的好时机取决于用例。我希望这件事是简单的,没有线程或调度程序。这种方法适合我。不像 SoftReference s、 保证对象在最短时间内可用。然而,在太阳变成红巨星之前,太阳不会留在记忆中。
例如,考虑一个响应缓慢的系统,该系统应能够检查最近是否完成了请求,在这种情况下,即使忙碌的用户多次点击按钮,也不能执行请求的操作两次。但是,如果一段时间后要求采取同样的行动,则应重新进行。

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

e0uiprwp5#

听起来ehcache对于您想要的东西来说太过了,但是请注意,它不需要外部配置文件。
通常,将配置移到声明性配置文件中是一个好主意(因此,当新安装需要不同的到期时间时,您不需要重新编译),但这完全不是必需的,您仍然可以通过编程方式对其进行配置。http://www.ehcache.org/documentation/user-guide/configuration

bpzcxfmw

bpzcxfmw6#

你可以试试过期Maphttp://www.java2s.com/code/java/collections-data-structure/expiringmap.htm 来自apachemina项目的类

uyto3xhc

uyto3xhc7#

如果有人需要一个简单的东西,下面是一个简单的密钥过期集。它可以很容易地转换成Map。

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

uz75evzq8#

这是一个示例实现,我为相同的需求和并发工作良好。可能对某人有用。

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链接(带侦听器实现)
https://github.com/vivekjustthink/weakconcurrenthashmap
干杯!!

uqjltbpv

uqjltbpv9#

guava缓存易于实现。我们可以使用guava缓存根据时间对密钥进行过期。我已经充分阅读了帖子和下面给出的我的学习重点。

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

              }

参考:guava缓存示例

knsnq2tg

knsnq2tg10#

apachecommons为map-to-expire条目提供了decorator:passiveexpiringmap它比guava的缓存更简单。
p、 小心,它不是同步的。

相关问题