2

在以下代码中:

private final Map<A, B> entriesMap = Collections
  .synchronizedMap(new HashMap<A, B>());

// ...

List<B> entries = new ArrayList<>(this.entriesMap.values());

如果entriesMap在其他方法中被多个线程访问/修改,是否有必要synchronize打开entriesMap?换句话说:

List<B> entries;

synchronize (this.entriesMap) {
  entries = new ArrayList<>(this.entriesMap.values());
}

如果我是正确的,values()不是原子操作,不像put()and get(),对吧?

谢谢!

4

4 回答 4

1

问题是,即使它values()本身是原子的,迭代它的行为也不是。构造ArrayList函数不能以原子方式获取值的副本 - 如果另一个线程在复制它们时更改了映射,则迭代器将失效。

于 2012-07-18T06:40:22.727 回答
1

好吧,调用值很可能是一个原子操作,但是它返回的 Collection 不是快照副本,而是由底层 Map 支持,因此当您在之后迭代 Map时(复制它时)对 Map 进行并发修改时,它会发出嘶哑的声音到 ArrayList 中)。

请注意,当只有一个线程时也会发生这种(ConcurrentModificationException),只要您以交错的方式迭代值并修改 Map,因此这并不是线程同步的真正问题。

进一步注意,有ConcurrentHashMap,它确实提供了一个快照迭代器,您可以在修改 Map 时进行迭代(修改不会反映在迭代器中)。但即使使用 ConcurrentHashMap,values() 的集合也不是快照,它的工作方式与普通 HashMap 一样。

于 2012-07-18T06:40:58.513 回答
0

是的你是对的。

将地图的值放入 中时ArrayList,将对这些值执行迭代。所以你需要同步块。请参阅此页面

于 2012-07-18T06:41:47.103 回答
0

Collections.synchronizedMap()保证您要在地图上运行的每个原子操作都会同步。并且values()也是 atomic ,但是当您将值放入时ArrayList,在这种情况下将不会同步您还需要同步列表。

于 2012-07-18T06:42:49.740 回答