有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

同步嵌套映射和集合(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

我对同步相当陌生,我想知道这是否是实现同步的正确方法 像这样同步嵌套的数据结构

谢谢你的帮助


共 (2) 个答案

  1. # 1 楼答案

    只需在ManagableMap上同步即可。一次只有一个线程可以获取ManagableMap上的锁,因此如果一个线程已经获取了ManagableMap上的锁,则不需要进一步锁定set和setMap,因为只有一个线程(锁定ManagableMap的线程)可以访问set和setMap

  2. # 2 楼答案

    同步作用于特定的对象实例,而不是包含引用的字段或变量,因此必须确保同步作用发生在相同的对象实例上,无论它们是否仅由局部变量引用

    在这种特殊情况下,IDEA无法静态检查代码是否符合您的要求,警告只是某种“代码气味”,提醒您效果可能不符合预期

    最好的办法是通过注销正在同步的实例来测试代码,并检查它们是否是您期望的实例——IDEA还可以在调试期间标记对象实例,以检查同步的对象是相同的还是不同的实例