我计划使用最多2个并发线程运行的CHM实现一个简单的内存缓存进行查找。一个线程使用迭代器迭代和更新CHM,第二个线程从地图读取值。
正如我的理解和迄今为止我所经历的那样,CHM Iterator是故障安全的,这意味着迭代将发生在数据快照上。
因此我们假设线程A使用密钥从CHM中提取一个POJO值,它正在迭代/更新POJO。同时,ThreadB可以获得相同的POJO。那么此时的预期行为是什么?
POJO如下所示。
Class Pojo{
private volatile long a;
private volatile long b;
....
public long getA() {
return this.a;
}
void setA(long a) {
this.a = a;
}
}
答案 0 :(得分:2)
正如我的理解和迄今为止我所经历的那样,CHM Iterator是安全故障的,这意味着迭代会发生在数据快照上。
这不正确。每the documentation:
类似地,Iterators,Spliterators和Enumerations在或从创建迭代器/枚举时返回反映哈希表状态的元素。
[强调我的]
因此我们假设线程A使用密钥从CHM中提取一个POJO值,它正在迭代/更新POJO。同时,ThreadB可以获得相同的POJO。那么此时的预期行为是什么呢?
如果线程A正在改变POJO而线程B正在检查相同的POJO,则ConcurrentHashMap根本不相关:两个线程如何 POJO并不重要POJO本身如何处理并发更新和读取。
你没有告诉过我们关于POJO类的任何信息,但是除非它经过精心设计以允许原子更新和读取,否则线程B有时会以不一致的状态查看POJO,或多或少都是这样的,一些线程A的读取但不是全部。
答案 1 :(得分:0)
你不能做这样的事。
Pojo myPojo = new Pojo();
myPojo.setA(10);
myPojo.setB(11);
// Atomic replace
CHM.replace(key, myPojo);
CHM替换是原子的,当替换正在进行时,没有其他线程会读取POJO的陈旧值。
答案 2 :(得分:0)
public Pojo setA(int newA ){ Pojo newPojo = new Pojo(newA, this.getB()); return newPojo; }
AtomicReference pojoRef = CHM.get(Key); Pojo oldPojo = pojoRef.get(); Pojo newPojo = oldPojo.setA(10); while(!pojoRef.compareAndSet(oldPojo, newPojo) ){ AtomicReference pojoRef = CHM.get(Key); Pojo oldPojo = pojoRef.get(); Pojo newPojo = oldPojo.setA(10); }