我在地图中的地图中有一个嵌套集,我试图通过两个线程进行同步。
地图实例化如下:
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。
我对同步很新,我想知道这是否是正确的方法 同步这样的嵌套数据结构。
谢谢你的帮助。
答案 0 :(得分:3)
您只需要在manageableMap上进行同步。一次只有一个线程可以获取manageableMap上的锁,因此如果一个线程获得了manageableMap上的锁,则不需要进一步锁定set和setMap,因为只有一个线程(锁定manageableMap的线程)可以访问set和setMap
答案 1 :(得分:1)
同步适用于特定对象实例,而不适用于保存对它们的引用的字段或变量,因此您必须确保在同一对象实例上发生同步,无论它们是否仅由局部变量重新引用。
在特殊情况下,IDEA无法静态检查代码是否符合您的要求,警告只是某种“代码味道”警告您效果可能与预期无关。
最好的办法是通过注销正在同步的实例来测试代码并检查它们是否是您期望的实例 - IDEA还有在调试期间标记对象实例的选项,以检查您同步的对象是否是相同或不同的实例。
答案 2 :(得分:1)
如果始终手动控制同步,则可能不需要使用Collections.synchronizedMap。在目标地图上同步的一个部分将会这样做。