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

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);
}
有帮助吗?

解决方案

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

如果someGlobalInstance.getMap()返回的对象始终是相同的,则同步块事实上确实使用准全局对象监视和代码产生预期的结果。

我也建议同意使用同步包装,如果你只需要到get() / put()同步调用,并没有任何大的synchronized块。但要确保该地图是的只有的通过包装访问或你就会有错误另一次机会。

另外请注意,如果someGlobalInstance.getMap()做的的返回相同的对象的时候,那么即使你的第二个代码示例将无法正常工作,甚至有可能比你原来的代码更糟,因为你可以同步上一个不同的对象比你呼吁get()之一。

其他提示

我认为代码可以是声音,这取决于的GetMap()方法的用途。如果它保持一个参考必须被线程之间共享的一个实例是有意义。警告是无关紧要,因为局部变量不会局部初始化。

我认为使用会更好 同步包装器 为你的地图

亚历克斯是正确的,添加通过调用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),而不是在方法中被创建检索,并且因此潜在地从其他线程访问。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top