Коллекция Java с истекающими записями - PullRequest
4 голосов
/ 23 февраля 2012

Мне нужно отслеживать определенные события в течение определенного периода времени и действовать, если число событий достигает определенного числа. Более подробно, я подключаюсь к внешней службе и отправляю запросы, которые подтверждаются со статусом, равным CONF или FAIL. Мне нужно иметь возможность отслеживать ответы, чтобы определить, получаю ли я необычное количество сбоев в данный период времени, например, > 3 не удается в течение последних 5 секунд, так что я могу проверить ошибки и действовать соответственно. В качестве альтернативы я мог бы проверить 3 ошибки подряд, но я предпочитаю подход, основанный на времени.

Я проверял CacheLoader в Guava после прочтения этой записи , но, хотя записи (я храню только FAIL-события) в Cache, похоже, истекают, как и ожидалось, вызов size() (чтобы определить количество сбоев) включает в себя также просроченные записи. Это похоже на то, как это должно работать в соответствии с документацией , если я не понял что-то неправильно ?? Есть ли способ получить количество «активных» событий из кэша?

Полагаю, альтернативным решением является использование CEP-фреймворка, такого как Esper, но это кажется излишним и громоздким для моих простых потребностей. У кого-нибудь есть совершенно другой подход, чтобы предположить, что облегчит мое требование? Спасибо

Ответы [ 4 ]

6 голосов
/ 23 февраля 2012

Получение точного количества активных элементов из Cache потребует блокировки всего кэша, что чрезвычайно дорого.Вы могли бы использовать метод cleanUp(), чтобы убедиться, что size не случайно подсчитывает записи, которые были тихо выселены.

Я бы не зависел от этой подачиВы точные результаты, но это должно значительно улучшить точность результатов.

1 голос
/ 22 ноября 2016

Вы можете украсить реализацию коллекции, чтобы сделать это.Как то так:

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);
    }
}
1 голос
/ 23 февраля 2012

Я думаю, что коллекция Guava с ближайшей функциональностью, к которой вы хотите, является MinMaxPriorityQueue с ограниченным максимальным размером. Вам нужно было бы поместить события отказа в хронологическом порядке и периодически проверять разницу между первым и последним элементом и его заполненность.

Но то, что вы, по сути, хотите, это метр. Вы можете попробовать этот метр из библиотеки метрик Coda Hale.

0 голосов
/ 23 февраля 2012

Я не использовал его, но похоже, что это может удовлетворить ваши потребности

...