【问题标题】:Synchronized and local copies of variables变量的同步和本地副本
【发布时间】:2010-12-12 20:11:42
【问题描述】:

我正在查看一些具有以下习语的遗留代码:

Map<String, Boolean> myMap = someGlobalInstance.getMap();
synchronized (myMap) {
    item = myMap.get(myKey);
}

我从 Intelli-J 的代码检查中得到的警告是:

Synchronization on local variable 'myMap'

这是适当的同步吗?为什么?

Map<String, Boolean> myMap = someGlobalInstance.getMap();
synchronized (someGlobalInstance.getMap()) {
    item = myMap.get(myKey);
}

【问题讨论】:

    标签: java intellij-idea synchronized thread-local


    【解决方案1】:

    这被标记为问题的原因是因为在局部变量上同步通常是一个坏主意。

    如果someGlobalInstance.getMap() 返回的对象总是相同的,那么同步块实际上确实使用了准全局对象监视器并且代码产生了预期的结果。

    我也同意使用同步包装器的建议,如果您只需要同步 get()/put() 调用并且没有任何更大的同步块。但请确保地图通过包装器访问,否则您将有另一个机会出现错误。

    另请注意,如果someGlobalInstance.getMap() 确实一直返回相同的对象,那么即使您的第二个代码示例也无法正常工作,它甚至可能比您的原始代码更糟糕,因为您可以在与您调用 get() 的对象不同的对象上同步。

    【讨论】:

    • 我有一个基于您回答的第一段的后续问题。你能解释一下为什么在局部变量上同步通常是一个坏主意吗?实例化方法内的字段是不是一个坏主意?
    • @Geek:关于同步的要点是您使用与其他线程共享的对象(否则它什么也不做)。如果您使用局部变量作为参考,情况可能会,也可能不会。
    【解决方案2】:

    我认为代码可能是正确的,这取决于 getMap() 方法的作用。如果它保留对必须在线程之间共享的实例的引用,那么它是有意义的。该警告无关紧要,因为局部变量未在本地初始化。

    【讨论】:

      【解决方案3】:

      我认为在您的地图中使用synchronized wrapper 会更好

      【讨论】:

        【解决方案4】:

        Alex 是正确的,通过调用 Collections.synchronizedMap(Map) 添加同步包装器是这里的典型方法。但是,如果您采用这种方法,可能仍然存在需要在Map 的锁上进行同步的情况;例如遍历地图时。

        Map<String, String> syncMap = Collections.synchronizedMap(new HashMap<String, String>());
        
        // Synchronized on map to prevent ConcurrentModificationException whilst iterating.
        synchronized (syncMap) {
          for (Map.Entry<String, String> entry : syncMap.entrySet()) {
            // Do work
          }
        }
        

        在您的示例中,可以忽略来自 IDEA 的警告,因为很明显您的局部变量:map 是从其他地方(someGlobalInstance)检索的,而不是在方法中创建的,因此可能会被访问来自其他线程。

        【讨论】:

          猜你喜欢
          • 2012-12-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多