我正在研究一个我可以肯定它与时间相关的错误,因为它在多个线程中使用。我认为我发现了可能是一个问题的代码,但是我想知道是否可以验证我的想法。
请考虑以下代码段:
public MyClass {
private Map<String, Map<String, String>> managedMap = Collections.synchronizedMap(new HashMap<>);
public purgeOldData() {
Map<String, Map<String, String>> cpyManagedMap = Collections.synchronizedMap(new HashMap<>(managedMap));
cpyManagedMap.forEach((primaryKey, pkMap) -> {
Map<String, String> cpyPkMap = new HashMap<>(pkMap);
cpyPkMap.forEach((secondKey, value) -> {
checkToPurge(primaryKey, pkMap, secondKey, value);
});
});
}
private checkToPurge(String primaryKey, Map pkMap, String secondKey, String value) {
synchronized (managedMap) {
if (someMethodThatReturnsBoolean()) {
pkMap.remove(secondKey);
if (pkMap.isEmpty()) {
managedMap.remove(primaryKey);
}
}
}
}
}
因此,managedMap是一个类成员,在整个类中都可以使用,必要时在同步块内使用。在purgeOldData()中,创建了ManagedMap的副本,并使副本同步。因此,cpyManagedMap是托管地图在特定时间的快照。
完成复制后,有几个循环可以最终获得我们要检查的数据。该数据被发送到checkToPurge()方法。在此方法内部,整个方法在原始ManagedMap上同步。
最后,我们回答了我的问题:
由于cpyManagedMap是及时的快照,难道不是在副本和checkToPurge()中的synch块之间的时间更新了ManagedMap吗?意味着该副本用于确定是否从原始ManagedMap中删除可能已更新的内容?
在这种情况下,真的需要同步cpyManagedMap吗?
如果确实我对mamagedMap可能被更新的担忧是真的,那么关于如何修复代码的任何建议?我是否应该将purgeOldData中的所有代码与managedMap同步?
谢谢!