All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.cloudhopper.commons.util.RunningTotal Maven / Gradle / Ivy

package com.cloudhopper.commons.util;

/*
 * #%L
 * ch-commons-util
 * %%
 * Copyright (C) 2012 Cloudhopper by Twitter
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */

// java imports
import java.util.Deque;
import java.util.ArrayDeque;
import java.util.concurrent.locks.*;

/**
 * Helps maintain a running total of X number of longs.  Internally,
 * this class maintains a list of X number of last long values.  Adding a new value
 * will evict the oldest value and the new running total will be recomputed.
 * The toString() method will return the running total.  If an average is preferred
 * then please considering using the RunningAverage class.
 *
 * NOTE: This class is thread-safe since its typical multiple threads would want
 * to call this class.  Internally, this uses a ReadWrite lock to ensure
 * efficient usage of this class.
 *
 * NOTE: This class internally stores the running total as a long -- avoid
 * using large values, otherwise this class may cause an overflow.
 *
 * @author joelauer (twitter: @jjlauer or http://twitter.com/jjlauer)
 */
public class RunningTotal {
    
    private long total;
    private int size;
    private Deque values;
    private final ReadWriteLock lock = new ReentrantReadWriteLock();
    private final Lock readLock = lock.readLock();
    private final Lock writeLock = lock.writeLock();

    public RunningTotal(int size) {
        this.total = 0;
        this.size = size;
        this.values = new ArrayDeque(size);
    }

    /**
     * Adds a new value to our running total. If the running total has already
     * reached its max size, this method will evict the oldest value.
     * 
* NOTE: This method will use a writeLock to ensure thread-safety. * @param value The new long value to add */ public void add(long value) { writeLock.lock(); try { // do we need to evict anything? if (this.values.size() >= this.size) { Long oldValue = this.values.pollFirst(); // subtract from running total this.total -= oldValue.longValue(); } // add this new value onto the end this.values.add(value); // add to our total this.total += value; } finally { writeLock.unlock(); } } /** * Returns current number of values in our running total. This should always * max out at the size value provided in our constructor. *
* NOTE: This method will use a readLock for thread-safety. * @return Current number of values in our running total. */ public long getSize() { readLock.lock(); try { return this.values.size(); } finally { readLock.unlock(); } } /** * Returns current value of our running total. *
* NOTE: This method will use a readLock for thread-safety. * @return The current running total. */ public long getTotal() { readLock.lock(); try { return this.total; } finally { readLock.unlock(); } } /** * Returns current average of our running total. *
* NOTE: This method will use a readLock for thread-safety. * @return The current average of our running total. */ public double getAverage() { readLock.lock(); try { // any values at all, needed to avoid a DivideByZero exception if (this.values.size() <= 0) { return 0; } return ((double)this.total / (double)this.values.size()); } finally { readLock.unlock(); } } /** * Returns a string representing the current running total. The same value * the toString() value a Long class would return. *
* NOTE: Will use a readLock to get a thread-safe version. * @return */ @Override public String toString() { return Long.toString(getTotal()); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy