变量的同步和本地副本

6ju8rftf  于 2021-06-30  发布在  Java
关注(0)|答案(4)|浏览(396)

我在看一些遗留代码,它有以下习惯用法:

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

dxpyg8gm1#

之所以将其标记为问题,是因为在局部变量上进行同步通常是个坏主意。
如果返回的对象 someGlobalInstance.getMap() 总是相同的,那么同步块实际上使用准全局对象监视,代码生成预期结果。
我也同意使用同步 Package 器的建议,如果您只需要同步 get() / put() 没有更大的同步块。但是要确保Map只能通过 Package 器访问,否则你会有另一个bug的机会。
还要注意,如果 someGlobalInstance.getMap() 如果不始终返回同一个对象,则即使是第二个代码示例也无法正常工作,甚至可能比原始代码更糟,因为您可以在不同于调用对象的对象上进行同步 get() 打开。

enxuqcxy

enxuqcxy2#

alex是正确的,通过调用 Collections.synchronizedMap(Map) 这是一种典型的方法。但是,如果您采用这种方法,可能仍然存在需要在服务器上同步的情况 Map 的锁;e、 在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 )而不是在方法中创建,因此可以从其他线程访问。

wf82jlnq

wf82jlnq3#

我认为最好对Map使用同步 Package 器

yks3o0rb

yks3o0rb4#

我认为代码可能是合理的,这取决于getmap()方法的作用。如果它保留对一个示例的引用,而该示例必须在线程之间共享,那么这是有意义的。警告是不相关的,因为局部变量没有在本地初始化。

相关问题