检查putIfAbsent的失败

时间:2016-07-31 13:17:27

标签: java java.util.concurrent concurrenthashmap

如果我希望避免不必要的包含调用,这是一个有效的代码吗? 我希望在每次调用时避免使用包含调用,因为这是高度时间敏感的代码。

cancelretryCountMap.putIfAbsent(tag,new AtomicInteger(0));
count = cancelretryCountMap.get(tag).incrementAndGet();
if(count > 10){
     ///abort after x retries
     ....
}

我正在使用 JDK 7

1 个答案:

答案 0 :(得分:0)

通常,您可以像这样使用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的原因是,您希望避免在“happy”路径中分配默认值(即,当已经存在具有给定键的条目时)。

如果没有匹配的条目,则必须使用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 ...
    }
}

请注意,这实际上已经在default上作为Map方法在JDK 8中提供,但由于您仍然使用JDK 7,因此您必须自行滚动,就像在此处所做的那样。

相关问题