Обычно вы будете использовать putIfAbsent
так:
final AtomicInteger present = map.get(tag);
int count;
if (present != null) {
count = present.incrementAndGet();
} else {
final AtomicInteger instance = new AtomicInteger(0);
final AtomicInteger marker = map.putIfAbsent(tag, instance);
if (marker == null) {
count = instance.incrementAndGet();
} else {
count = marker.incrementAndGet();
}
}
Причины явных get
существ, что вы хотите, чтобы избежать распределения значение по умолчанию в «счастливом» пути (т. е. когда уже есть запись с заданным ключом).
Если нет соответствующей записи, вы должны использовать возвращаемое значение putIfAbsent
для того, чтобы различать
- запись по-прежнему отсутствует (и было добавлено значение по умолчанию из-за вызов), в этом случае метод возвращает
null
и
- другого поток выиграл гонку и вставил новую запись после вызова
get
(в этом случае метод возвращает текущее значение, связанное с данным ключом)
Вы можете абстрактный эту последовательность, вводя вспомогательный метод, например,
interface Supplier<T> {
T get();
}
static <T> T computeIfAbsent(ConcurrentMap<K,T> map, T key, Supplier<? extends T> producer) {
final T present = map.get(key);
if (present != null) {
return present;
} else {
final T fallback = producer.get();
final T marker = map.putIfAbsent(key, fallback);
if (marker == null) {
return fallback;
} else {
return marker;
}
}
}
Вы можете использовать это в вашем примере:
static final Supplier<AtomicInteger> newAtomicInteger = new Supplier<AtomicInteger>() {
public AtomicInteger get() { return new AtomicInteger(0); }
};
void yourMethodWhatever(Object tag) {
final AtomicInteger counter = computeIfAbsent(cancelretryCountMap, tag, newAtomicInteger);
if (counter.incrementAndGet() > 10) {
... whatever ...
}
}
Обратите внимание, что это на самом деле уже предусмотрено в JDK 8, default
метод на Map
, но так как вы все еще на JDK 7, вам нужно катиться самостоятельно, как это делается здесь.