变量的同步和本地副本
我正在查看一些具有以下习惯用法的遗留代码:
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);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
这被标记为问题的原因是因为同步局部变量通常是一个坏主意。
如果由
someGlobalInstance.getMap()
返回的对象始终相同,那么同步块实际上使用了准全局对象监视器,并且代码产生了预期的结果。如果您只需要同步
get()
/put()
调用并且没有任何更大的同步块,我也同意使用同步包装器的建议。但请确保地图仅通过包装器访问,否则您将有另一个出现错误的机会。另请注意,如果
someGlobalInstance.getMap()
确实不始终返回同一对象,那么即使您的第二个代码示例也无法正常工作,甚至可能比您的原始代码,因为您可以在与调用get()
的对象不同的对象上进行同步。The reason this is flagged as a problem is because synchronizing on local variables is usually a bad idea.
If the object returned by
someGlobalInstance.getMap()
is always the same, then the synchronized block does in fact use that quasi-global objects monitor and the code produces the expected result.I also agree with the suggestion to use a synchronized wrapper, if you only need to synchronize the
get()
/put()
calls and don't have any bigger synchronized blocks. But make sure that the Map is only accessed via the wrapper or you'll have another chance for bugs.Also note that if
someGlobalInstance.getMap()
does not return the same object all the time, then even your second code example will not work correctly, it could even be worse than your original code since you could synchronize on a different object than the one you callget()
on.我认为代码可能是合理的,具体取决于 getMap() 方法的作用。如果它保留对必须在线程之间共享的实例的引用,那就有意义了。该警告无关紧要,因为局部变量未在本地初始化。
I think the code could be sound, depending on what the getMap() method does. If it keeps a reference to an instance that has to be shared between threads it makes sense. The warning is irrelevant since the local variable is not initialized locally.
我认为最好使用 地图的同步包装
I think it would be better to use synchronized wrapper for your map
Alex 是正确的,通过调用 Collections.synchronizedMap(Map) 添加同步包装器是这里的典型方法。但是,如果您采用这种方法,在某些情况下您可能仍然需要同步
Map
的锁;例如,当迭代地图时。在您的示例中,来自 IDEA 的警告可以被忽略,因为很明显您的局部变量:
map
是从其他地方 (someGlobalInstance
) 检索的,而不是在方法内创建的,因此可以从其他线程访问。Alex is correct in that adding a synchronized wrapper by calling
Collections.synchronizedMap(Map)
is a typical approach here. However, if you take this approach there may still be situations where you need to synchronized on theMap
's lock; e.g. when iterating over the map.In your example, the warning from IDEA can be ignored, as it's evident that your local variable:
map
is retrieved from somewhere else (someGlobalInstance
) rather than being created within the method, and can therefore potentially be accessed from other threads.