Java 如何处理对存储在映射中的POJO的并发更新和读取
我计划使用最多由2个并发线程操作的CHM实现一个用于查找的简单内存缓存。一个线程使用迭代器迭代和更新CHM,第二个线程从映射中读取值 根据我的理解,我到目前为止所经历的CHM迭代器是故障安全的,这意味着迭代将发生在数据的快照上 因此,假设线程A从CHM中提取一个值,该值是使用键的POJO,并且它正在迭代/更新POJO。同时,ThreadB在同一个POJO上运行。那么,此时的预期行为是什么呢Java 如何处理对存储在映射中的POJO的并发更新和读取,java,multithreading,concurrency,java.util.concurrent,concurrenthashmap,Java,Multithreading,Concurrency,Java.util.concurrent,Concurrenthashmap,我计划使用最多由2个并发线程操作的CHM实现一个用于查找的简单内存缓存。一个线程使用迭代器迭代和更新CHM,第二个线程从映射中读取值 根据我的理解,我到目前为止所经历的CHM迭代器是故障安全的,这意味着迭代将发生在数据的快照上 因此,假设线程A从CHM中提取一个值,该值是使用键的POJO,并且它正在迭代/更新POJO。同时,ThreadB在同一个POJO上运行。那么,此时的预期行为是什么呢 ThreadB会看到ThreadA正在进行的更新吗?我猜不是因为线程仍然在进行更新。 如果是,请分享您的
- ThreadB会看到ThreadA正在进行的更新吗?我猜不是因为线程仍然在进行更新。<李>
- 如果是,请分享您的想法,这将如何发生
- 如果没有,请建议有效的替代方法,如果你已经实施了
Class Pojo{
private volatile long a;
private volatile long b;
....
public long getA() {
return this.a;
}
void setA(long a) {
this.a = a;
}
}
根据我的理解,我到目前为止所经历的CHM迭代器是故障安全的,这意味着迭代将发生在数据的快照上
这是不对的。Per:
类似地,迭代器、拆分器和枚举返回元素,这些元素反映了在或在创建迭代器/枚举后某个点的哈希表状态
[我的重点]
因此,假设线程A从CHM中提取一个值,该值是使用键的POJO,并且它正在迭代/更新POJO。同时,ThreadB在同一个POJO上运行。那么,此时的预期行为是什么呢 如果线程A正在变异一个POJO,而线程B正在检查同一个POJO,那么ConcurrentHashMap一点也不相关:这两个线程如何获得POJO无关紧要,只有POJO本身如何处理并发更新和读取
您还没有告诉我们关于POJO类的任何信息,但除非它经过精心设计,允许原子更新和读取,否则它或多或少是一种假设,即线程B有时会在不一致的状态下查看POJO,其中包含一些线程a的读取,但不是所有的读取。您不能这样做吗
Pojo myPojo = new Pojo();
myPojo.setA(10);
myPojo.setB(11);
// Atomic replace
CHM.replace(key, myPojo);
CHM replace是原子的,在进行替换时,其他线程不会读取POJO的过时值。- CHM的值应该是原子引用
- 使Pojo类不可变,更新任何新值都会创建一个新的Pojo对象李>
- 实现一个接受构造函数中所有参数的构造函数
- 实现每个set方法,如下面给出的示例
- 更新CHM时,请遵循以下步骤
这是为了学习还是为了生产?如果是用于生产,请使用经过战斗测试的东西:即使POJO类经过精心设计,允许原子更新/读取,但如果写入是在读取之后启动的,则仍有可能丢失更新。@CKK:我认为这是给定的--没有人希望读取将来进行,也不是为了写过去。这就是为什么OP需要重新考虑使用
ConcurrentHashMap
,因为仍然无法保证不会错过OP想要的更新。更好的方法是使用BlockingQueue
,其中一个线程创建并将POJO写入队列,另一个线程读取POJO。通过这种方法,可以保证写操作不会丢失,并且您还可以获得并行化功能。@CKing:我不确定您是如何确定“OP想要的”是“保证更新不会丢失”;这完全不是我如何解释他/她想要“查找缓存”的愿望。“THeTrad能看到ththa正在做的更新吗?我想不是因为thela还在进行更新。”“如果是,请分享你的想法,这将如何发生”。。和。。“如果没有,请建议有效的替代方法,如果您已经实施了任何。”。对我来说,这些都清楚地表明OP希望找到解决这些问题的方法。特别是解决这些问题的替代解决方案的最后一点。这就是说,你是对的,OP需要缓存,所以阻塞队列没有意义。
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);
}