我正在维护使用ConcurrentHashMap
的多线程旧代码。
其他方法中有添加和删除操作。
在以下代码中,在从映射中收集了几个值之后的某个时刻,它在执行NullPointerException
时抛出synchronize(value)
。
public class MyClass{
private final Map<MyObj, Map<String, List<String>>> conMap = new ConcurrentHashMap<>();
//...
public void doSomthing((MyObj id){
List<Map<String, List<String>>> mapsList = new LinkedList<>();
for(MyObj objId: conMap.keySet()){
if(objId.key1.equals(id.key1)){
mapsList.add(conMap.get(objId));
}
}
for(Map<String, List<String>> map: mapsList){
synchronized(map){ // <-- NullPointerException here
//...
}
}
//...
}
我觉得也许在第一个循环的迭代过程中,记录正在被删除。而当行:
mapsList.add(conMap.get(objId));
正在执行,objId
不再存在,mapsList
添加空值,因此在第二个循环NullPoinerException
中被抛出。
还有其他原因导致此异常吗?
答案 0 :(得分:1)
您迷上了Check-Then-Act反模式。它意味着检查条件(如键的存在),然后对其进行操作(如调用get
),而忽略条件在其间可能发生变化的可能性。
因此,在遍历conMap.keySet()
时会遇到一个特定的键,但是当您调用conMap.get(objId)
时,该键可能不再在映射中,这通过返回{{1 }}。
强烈建议使用具有合适的null
/ hashCode
实现的键类型,因此您无需遍历整个地图来查找匹配项,而可以使用单个{{1 }}。
但是,当您必须遍历地图并需要值时,请遍历条目集而不是键集。
equals