[英]How data is stored/accessed and preventing race conditions in maps, java
我们有这样一个案例。
class A{
class foo{
//Map with a lot of entries
private HashMap<String,String> dataMap;
public updater(){
// updates dataMap
// takes several milliseconds
}
public someAction(){
// needs to perform read on dataMap
// several times, in a long process
// which takes several milliseconds
}
}
问题是, someAction 和 updater 都可以同时调用, someAction 是一个更频繁的方法。 如果调用 updater,它可以从 dataMap 中替换很多值。 我们需要 readAction 的一致性。 如果该方法以旧数据映射开始,则所有读取都应使用旧数据映射进行。
class foo{
//Map with a lot of entries
private HashMap<String,String> dataMap;
public updater(){
var updateDataMap = clone(dataMap); // some way to clone data from map
// updates updateDataMap instead of dataMap
// takes several milliseconds
this.dataMap = updateDataMap;
}
public someAction(){
var readDataMap = dataMap;
// reads from readDataMap instead of dataMap
// several times, in a long process
// which takes several milliseconds
}
}
这能确保一致性吗? 我相信克隆方法会在 memory 中分配一个不同的区域,并且会从那里发生新的引用。 是否会对性能产生任何影响? 而oldDataMap的memory用完后会放出来吗?
如果这是正确的方法,还有其他有效的方法可以实现吗?
我相信您的方法会奏效,因为updater()
的所有更改都将发生在(深层)副本中,并且someAction()
将不可见,直到在单个操作中更新了引用。
我理解您并不关心someAction()
是否看到最新版本的地图内容,只要 map 是一致的,即在更新过程中没有观察到。 在这种情况下,您的someAction()
无法查看不完整的 map。
请注意,最多 1 个线程应该能够调用updater()
- 两个线程同时调用它意味着只有一个线程可以写入更新的 map。 我建议进行以下更改:
// no synchronization needed at this level, but volatile is important
private volatile HashMap<String,String> dataMap = new HashMap<>;
// if two threads attempt to call this at once, one blocks until the other finishes
public synchronized updater() {
var writeDataMap = clone(dataMap); // a deep copy
// update writeDataMap - guaranteed no other thread updating
// ... long operation
dataMap = writeDataMap; // switch visible map with the updated one
}
public someAction() {
var readDataMap = dataMap;
// process readDataMap - guaranteed not to change while being read
// ... long operation
}
这里的重要关键字是volatile ,以确保在updater()
完成其工作后,其他线程可以访问更新的 map。 使用同步只是防止多个updater()
线程相互干扰,并且主要是防御性的。
如果您想避免复制,您可以使用java.util.concurrent.locks.ReentrantReadWriteLock
来保护对 map 的访问。 在updater
中使用写锁,在someAction
中使用读锁。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.