我正在尝试找到这些问题的答案,但无法在Google或Java文档中理解(或确认)它。
我的实现如下:
Map<String, POJO> map = new ConcurrentHashMap<String, POJO>();
如果我愿意
value1 = map.get(key1);
value1.setProp(prop);
任何其他线程都可以覆盖。
现在,我正在考虑是否要执行以下操作:这将是原子操作/换句话说,它将阻塞key1段?
map.compute(key1, (key1, value1) -> { value1.setProp(prop) });
用于compute
函数的Javadoc
尝试计算指定键及其当前键的映射 映射值(如果没有当前映射,则为null)。整个 方法调用是原子执行的。一些尝试更新 其他线程对此地图进行的操作可能会在 计算正在进行中,因此计算应简短且 简单,并且不得尝试更新此Map的任何其他映射。
参考文献:
1。https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html 2。https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html#compute-K-java.util.function.BiFunction-
在我的最终实现中,我做了这样的事情,因为所有线程都共享NewMap,最后,我列出了POJO的新列表
抽象数据类型
public class NewMap {
private Map<String, POJO> map;
private boolean isUpdatable;
void NewMap(){
isUpdatable = true;
map = new ConcurrentHashMap();
}
void putPOJOProp1(String key, Type value) throws ReadOnlyException{
map.compute(key, (k,v) -> {
if(!isUpdatable) throw new ReadOnlyException();
if(k == null){
POJO p = new POJO();
p.setProp1(value);
v = p;
} else {
v = v.setProp1(v)
}
});
}
void putPOJOProp2....
void putPOJOProp3....
List<POJO> getAll() {
isUpdatable = false;
List<POJO> pojos;
for(key: map.getKeys()) {
Pojo p = map.get(key);
p.setKey(key);
pojos.add(p);
}
return pojos;
}
}
答案 0 :(得分:8)
您会混淆两个不同的术语。
ConcurrentHashMap
防止内部结构损坏,但不能防止竞争条件。如果您只想避免数据损坏,那么使用ConcurrentHashMap
是有效的。
但是从您的问题看来,您似乎正在努力避免比赛条件。 ConcurrentHashMap
不会以任何方式保护您免受他们侵害。
为了更好地理解它,让我们看下面的示例:
Map<String, POJO> map = new ConcurrentHashMap<>();
ExecutorService pool = Executors.newWorkStealingPool(10);
for (int t = 0; t < 10; t++) {
pool.execute(() -> {
for (int i = 0; i < 100_000; i++) {
map.compute("A", (k, v) -> {
if (v == null) {
return new POJO();
}
v.a = ++v.a;
v.b = ++v.b;
return v;
});
}
});
}
pool.awaitTermination(5, TimeUnit.SECONDS);
System.out.println(map);
// With POJO like
class POJO {
// toString() here
Integer a = 1;
Integer b = 1;
}
在这里我们得到{A=POJO{a=1000000, b=1000000}}
,因此我们的操作是线程安全的。如果您只想得到这些,那就没事了。
答案 1 :(得分:8)
ConcurrentHashMap.compute状态的Javadoc
整个方法调用是原子执行的。
请注意,相比之下ConcurrentSkipListMap.compute
不是原子的。
Alexey Soshin回答的更紧凑形式是
Map<String, long[]> map = new ConcurrentSkipListMap<>();
map.put("A", new long[2]);
IntStream.range(0, 1_000_000)
.parallel()
.forEach(i -> map.compute("A", (k, v) -> {
v[0]++;
v[1]++;
return v;
}));
System.out.println(Arrays.toString(map.get("A")));
打印类似
[643553, 597254]
c.f。 HashMap产生类似
[244786, 245993]
但是,使用ConcurrentHashMap
可以达到预期的效果
[1000000, 1000000]