我有一个ConcurrentHashMap,我想保证.get和.put操作是原子的。

根据我的分析,这里不是我可以选择计算的原因,因为我必须在else块中做一些重要的事情。
你知道我怎么能做到吗?

这是代码-如果您需要更多信息,请告诉我

private Map<String, Long> ids = new ConcurrentHashMap<>();
ids.putIfAbsent(mapKey, 0L);
Long newId = generateId(mapKey);
if (newId > ids.get(mapKey)) {
   ids.put(mapKey, newId);
   return newId;
} else {
   // do something else
}

最佳答案

您可以将Map与AtomicLong结合使用:Map通过每个mapKey获取AtomicLong,然后在AtomicLong上获取compareAndSet以获得所需的原子性。

private Map<String, AtomicLong> ids = new ConcurrentHashMap<>();
ids.putIfAbsent(mapKey, new AtomicLong());
AtomicLong idForKey = ids.get(mapKey);
// Optionally, those two lines can be shorted to:
//   ids.computeIfAbsent(mapKey, k -> new AtomicLong())

long newId = generateId(mapKey);
long origId = idForKey.get();
if (newId > origId && idForKey.compareAndSet(origId, newId)) {
   return newId;
} else {
   // do something else
}


这将确保仅在能够安装严格增加的ID的情况下才返回newId。如果有人在您之前(特别是在idForKey.get()compareAndSet之间)进入,那么您仍然会生成newId,但是您将不会使用update AtomicLong,并且您将进入// do something else块。

08-04 16:02