同步嵌套映射和集合(Java)
我在一个映射中有一个嵌套集,我正试图通过两个线程同步该映射
地图被实例化为:
private final Map<Manageable, Map<String, Set<Manageable>>> manageableMap =
Collections.synchronizedMap(new HashMap<Manageable, Map<String, Set<Manageable>>>());
这是我用来向地图添加值的函数:
private void put(Manageable key, Manageable value, String valueType) {
synchronized (manageableMap) {
Map<String, Set<Manageable>> setMap = manageableMap.get(key);
if (setMap == null) {
setMap = new HashMap<String, Set<Manageable>>();
manageableMap.put(key, Collections.synchronizedMap(setMap));
}
synchronized (setMap) {
Set<Manageable> set = setMap.get(valueType);
if (set == null) {
set = new HashSet<Manageable>();
setMap.put(valueType, Collections.synchronizedSet(set));
}
synchronized (set) {
set.add(value);
}
}
}
}
Intellij IDEA警告我,我正在同步局部变量setMap和set
我对同步相当陌生,我想知道这是否是实现同步的正确方法 像这样同步嵌套的数据结构
谢谢你的帮助
# 1 楼答案
只需在ManagableMap上同步即可。一次只有一个线程可以获取ManagableMap上的锁,因此如果一个线程已经获取了ManagableMap上的锁,则不需要进一步锁定set和setMap,因为只有一个线程(锁定ManagableMap的线程)可以访问set和setMap
# 2 楼答案
同步作用于特定的对象实例,而不是包含引用的字段或变量,因此必须确保同步作用发生在相同的对象实例上,无论它们是否仅由局部变量引用
在这种特殊情况下,IDEA无法静态检查代码是否符合您的要求,警告只是某种“代码气味”,提醒您效果可能不符合预期
最好的办法是通过注销正在同步的实例来测试代码,并检查它们是否是您期望的实例——IDEA还可以在调试期间标记对象实例,以检查同步的对象是相同的还是不同的实例