/*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
package jsr166e;
import jsr166e.LongAdder;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;
import java.util.Set;
import java.io.Serializable;
/**
* A keyed table of adders, that may be useful in computing frequency
* counts and histograms, or may be used a form of multiset. A {@link
* LongAdder} is associated with each key. Keys are added to the table
* implicitly upon any attempt to update, or may be added explicitly
* using method {@link #install}.
*
*
jsr166e note: This class is targeted to be placed in
* java.util.concurrent.atomic
*
* @author Doug Lea
*/
public class LongAdderTable implements Serializable {
/** Relies on default serialization */
private static final long serialVersionUID = 7249369246863182397L;
/** Concurrency parameter for map -- we assume high contention */
private static final int MAP_SEGMENTS =
Math.max(16, Runtime.getRuntime().availableProcessors());
/** The underlying map */
private final ConcurrentHashMap map;
/**
* Creates a new empty table.
*/
public LongAdderTable() {
map = new ConcurrentHashMap(16, 0.75f, MAP_SEGMENTS);
}
/**
* If the given key does not already exist in the table, inserts
* the key with initial sum of zero; in either case returning the
* adder associated with this key.
*
* @param key the key
* @return the adder associated with the key
*/
public LongAdder install(K key) {
LongAdder a = map.get(key);
if (a == null) {
LongAdder r = new LongAdder();
if ((a = map.putIfAbsent(key, r)) == null)
a = r;
}
return a;
}
/**
* Adds the given value to the sum associated with the given
* key. If the key does not already exist in the table, it is
* inserted.
*
* @param key the key
* @param x the value to add
*/
public void add(K key, long x) {
LongAdder a = map.get(key);
if (a == null) {
LongAdder r = new LongAdder();
if ((a = map.putIfAbsent(key, r)) == null)
a = r;
}
a.add(x);
}
/**
* Increments the sum associated with the given key. If the key
* does not already exist in the table, it is inserted.
*
* @param key the key
*/
public void increment(K key) { add(key, 1L); }
/**
* Decrements the sum associated with the given key. If the key
* does not already exist in the table, it is inserted.
*
* @param key the key
*/
public void decrement(K key) { add(key, -1L); }
/**
* Returns the sum associated with the given key, or zero if the
* key does not currently exist in the table.
*
* @param key the key
* @return the sum associated with the key, or zero if the key is
* not in the table
*/
public long sum(K key) {
LongAdder a = map.get(key);
return a == null ? 0L : a.sum();
}
/**
* Resets the sum associated with the given key to zero if the key
* exists in the table. This method does NOT add or
* remove the key from the table (see {@link #remove}).
*
* @param key the key
*/
public void reset(K key) {
LongAdder a = map.get(key);
if (a != null)
a.reset();
}
/**
* Resets the sum associated with the given key to zero if the key
* exists in the table. This method does NOT add or
* remove the key from the table (see {@link #remove}).
*
* @param key the key
* @return the previous sum, or zero if the key is not
* in the table
*/
public long sumThenReset(K key) {
LongAdder a = map.get(key);
return a == null ? 0L : a.sumThenReset();
}
/**
* Returns the sum totalled across all keys.
*
* @return the sum totalled across all keys.
*/
public long sumAll() {
long sum = 0L;
for (LongAdder a : map.values())
sum += a.sum();
return sum;
}
/**
* Resets the sum associated with each key to zero.
*/
public void resetAll() {
for (LongAdder a : map.values())
a.reset();
}
/**
* Totals, then resets, the sums associated with all keys.
*
* @return the sum totalled across all keys.
*/
public long sumThenResetAll() {
long sum = 0L;
for (LongAdder a : map.values())
sum += a.sumThenReset();
return sum;
}
/**
* Removes the given key from the table.
*
* @param key the key
*/
public void remove(K key) { map.remove(key); }
/**
* Removes all keys from the table.
*/
public void removeAll() { map.clear(); }
/**
* Returns the current set of keys.
*
* @return the current set of keys
*/
public Set keySet() {
return map.keySet();
}
/**
* Returns the current set of key-value mappings.
*
* @return the current set of key-value mappings
*/
public Set> entrySet() {
return map.entrySet();
}
}