rajesh
rajesh

Reputation: 3407

Java counter with value for last one hour

I need a counter which will get incremented as certain tasks are complete. We need the value for only last one hour, ie the window will be moving and not for static hours.

What is the best way to go about this? One way I could think of was having an array of size 60, one for each minute and update the entry for respective minute and do a total of this on a get(). On turning to a new minute, the array will be reset.

Are there better solutions? Any time based implementations of Counter available?

Upvotes: 3

Views: 2442

Answers (3)

Christian d'Heureuse
Christian d'Heureuse

Reputation: 5630

I have written the Java class DecayingCounter for this purpose.

It uses the following formulas to implement an exponentially time-decaying counter:

tau = halfLifeInSeconds / Math.log(2.0)
value *= Math.exp(deltaTimeInNanos * -1E-9 / tau)

Upvotes: 3

AxelH
AxelH

Reputation: 14572

For simpler technique, but nice reading from Artur !

You could simply use a List to store every time needed. Then filter those when you get the list.

private static List<Long> counter = new LinkedList<Long>(); //Thanks to Artur to point that out. (Faster but a Queue takes more memory)
public static final long FILTER_TIME = 1000*60*60;

public static void add(){
    add(System.currentTimeMillis());
}

public static List<Long> get(){
    filter();
    return counter;
}

private static void filter(){
    int length = counter.size();
    long lastHour = System.currentTimeMillis() - 1000*60*60;

    //trim from left until value is correct or list is empty
    while(length > 0 && counter.get(0) < lastHour){
        counter.remove(0);
        length--;
    }
}

The result will be a list (sorted since the add method only add currentTime) without older value. This is basic implementation, better technics could be used but for a quick solution. This could do it.

The filter is done on the getter. This means that the list could explode in length if this reading is done rarely. So this could be done in the add method also.

Upvotes: 1

Artur Biesiadowski
Artur Biesiadowski

Reputation: 3698

You can implement some kind of array, which will give you best values (and can be used to draw graphs, etc). But if you are interested in doing it in single value, there is a trick to get proper approximation. It is used for example in loadavg computation on unix https://en.wikipedia.org/wiki/Load_(computing)#Unix-style_load_calculation

Systems calculate the load average as the exponentially damped/weighted moving average of the load number. The three values of load average refer to the past one, five, and fifteen minutes of system operation.[2]

Mathematically speaking, all three values always average all the system load since the system started up. They all decay exponentially, but they decay at different speed: they decay exponentially by e after 1, 5, and 15 minutes respectively. Hence, the 1-minute load average will add up 63% (more precisely: 1 - 1/e) of the load from last minute, plus 37% (1/e) of the load since start up excluding the last minute. For the 5 and 15 minute load average, the same 63%/37% ratio is computed throughout 5 minutes, and 15 minutes respectively. Therefore, it's not technically accurate that the 1-minute load average only includes the last 60 seconds activity (since it still includes 37% activity from the past), but that includes mostly the last minute.

Computing moving average on single value - there are multiple possibilities, described in detail, with some proofs here https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average

Best one for your use case is probably this one https://en.wikipedia.org/wiki/Moving_average#Application_to_measuring_computer_performance

equation

Upvotes: 2

Related Questions