我有一个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
块。