变量的同步和本地副本

时间:2009-11-03 22:45:04

标签: java intellij-idea synchronized thread-local

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

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);
}

4 个答案:

答案 0 :(得分:12)

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

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

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

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

答案 1 :(得分:4)

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

答案 2 :(得分:2)

我认为最好将[{3}}用于地图

答案 3 :(得分:2)

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)检索的,而不是在方法中创建的,并且可以因此可能从其他线程访问。