简体   繁体   English

带有过期条目的Java集合

[英]Java collection with expiring entries

I need to track certain events over a specified time frame and act if the number of events reaches a certain number. 我需要在指定的时间范围内跟踪某些事件,并在事件数量达到一定数量时采取行动。 In more detail, I connect to an external service and submit requests which are acknowledged with a status that equals CONF or FAIL. 更详细地说,我连接到外部服务并提交已确认状态等于CONF或FAIL的请求。 I need to be able to monitor the responses to detect if I get an unusual number of fails in a given time frame, eg >3 fails during the last 5 seconds, so that I can check for errors and act accordingly. 我需要能够监视响应以检测我是否在给定时间范围内得到异常数量的失败,例如> 3在最后5秒内失败,以便我可以检查错误并采取相应措施。 I could alternatively check for 3 fails in a row but I prefer a time based approach. 我可以选择连续3次检查,但我更喜欢基于时间的方法。

I have been testing Guava's CacheLoader after reading this post but while entries (I only store FAIL-events) in the Cache appears to expire as expected, a call to size() (to determine number of fails) includes also the expired entries. 我在阅读这篇文章后一直在测试Guava的CacheLoader ,但是当缓存中的条目(我只存储FAIL事件)似乎按预期到期时,对size()的调用(以确定失败次数)也包括过期的条目。 This appears to be how it is supposed to work according to the documentation , if I have not misunderstood things?? 如果我没有误解事情,这似乎是根据文档应该如何工作? Is there any way to get the number of 'active' events from a Cache? 有没有办法从缓存中获取“活动”事件的数量?

I guess an alternative solution is to use a CEP-framework like Esper but it seems like overkill and cumbersome for my simple needs. 我想另一种解决方案是使用像Esper这样的CEP框架,但对于我的简单需求来说似乎有点过分和麻烦。 Does anyone have a completely different approach to suggest that would facilitate my requirement? 有没有人有一个完全不同的方法来建议这将有助于我的要求? Thanks 谢谢

Getting the exact number of active elements from the Cache would require locking the entire cache, which is extremely expensive. Cache获取确切数量的活动元素需要锁定整个缓存,这非常昂贵。 You might be able to use the cleanUp() method to make sure that size is not accidentally counting entries that have been quietly evicted, though. 您可以使用cleanUp()方法来确保size不会意外地计算已被悄悄驱逐的条目。

I would not depend on this giving you exact results, but it should improve the accuracy of the results significantly. 我不会依赖于此给出确切的结果,但它应该显着提高结果的准确性。

You could decorate a collection implementation to do that. 你可以装饰一个集合实现来做到这一点。 Something like this: 像这样的东西:

public class ExpirableArrayList<E> extends ArrayList<E> {

    private final Date creation = new Date();

    private final long timeToLiveInMs;

    public ExpirableArrayList(long timeToLiveInMs, int initialCapacity) {
        super(initialCapacity);
        this.timeToLiveInMs = timeToLiveInMs;
    }

    public ExpirableArrayList(long timeToLiveInMs) {
        this.timeToLiveInMs = timeToLiveInMs;
    }

    public ExpirableArrayList(long timeToLiveInMs, Collection<? extends E> c) {
        super(c);
        this.timeToLiveInMs = timeToLiveInMs;
    }

    private void expire() {
        if (System.currentTimeMillis() - creation.getTime() > timeToLiveInMs) {
            clear();
        }
    }

    @Override
    public int size() {
        expire();
        return super.size();
    }

    @Override
    public boolean isEmpty() {
        expire();
        return super.isEmpty();
    }

    @Override
    public boolean contains(Object o) {
        expire();
        return super.contains(o);
    }

    @Override
    public Iterator<E> iterator() {
        expire();
        return super.iterator();
    }

    @Override
    public Object[] toArray() {
        expire();
        return super.toArray();
    }

    @Override
    public <T> T[] toArray(T[] a) {
        expire();
        return super.toArray(a);
    }

    @Override
    public boolean add(E e) {
        expire();
        return super.add(e);
    }

    @Override
    public boolean remove(Object o) {
        expire();
        return super.remove(o);
    }

    @Override
    public boolean containsAll(Collection<?> c) {
        expire();
        return super.contains(c);
    }

    @Override
    public boolean addAll(Collection<? extends E> c) {
        expire();
        return super.addAll(c);
    }

    @Override
    public boolean addAll(int index, Collection<? extends E> c) {
        expire();
        return super.addAll(index, c);
    }

    @Override
    public boolean removeAll(Collection<?> c) {
        expire();
        return super.removeAll(c);
    }

    @Override
    public boolean retainAll(Collection<?> c) {
        expire();
        return super.retainAll(c);
    }

    @Override
    public E get(int index) {
        expire();
        return super.get(index);
    }

    @Override
    public E set(int index, E element) {
        expire();
        return super.set(index, element);
    }

    @Override
    public E remove(int index) {
        expire();
        return super.remove(index);
    }

    @Override
    public int indexOf(Object o) {
        expire();
        return indexOf(o);
    }

    @Override
    public int lastIndexOf(Object o) {
        expire();
        return lastIndexOf(o);
    }

    @Override
    public ListIterator<E> listIterator() {
        expire();
        return listIterator();
    }

    @Override
    public ListIterator<E> listIterator(int index) {
        expire();
        return listIterator();
    }

    @Override
    public List<E> subList(int fromIndex, int toIndex) {
        expire();
        return subList(fromIndex, toIndex);
    }
}

I think Guava collection with the nearest functionality to what you want is MinMaxPriorityQueue with a limited maximum size. 我认为具有最接近功能的Guava集合是具有有限最大尺寸的MinMaxPriorityQueue You'd have to put failure events in chronological order and check periodically for the difference between first and last element and whether it is full. 您必须按时间顺序放置故障事件,并定期检查第一个和最后一个元素之间的差异以及它是否已满。

But what you essentially want is a meter. 但你真正想要的是一个仪表。 You can try this Meter from Coda Hale's Metrics library. 您可以从Coda Hale的Metrics库中试用这台仪表

我没有使用它,但看起来可能满足您的需求

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM