线程安全的方式来复制HashMap

时间:2018-02-14 00:13:01

标签: java

我有一个场景,我想以一种线程安全的方式将HashMap复制到一个新的HashMap中。我想这样做是为了避免在复制地图时出现任何并发修改异常。

2 个答案:

答案 0 :(得分:2)

您需要确保在创建新地图时不会修改原始HashMap。最直接的方法是在原始地图上进行同步:

HashMap<K, V> original = ...

HashMap<K, V> copy;
synchronized (original) {
    copy = new HashMap<>(original);
}

如果所有可能修改original的代码在同一个对象(original本身上同步,在我的示例代码中,虽然它可以是任何共享对象,但这只能以线程安全的方式工作)。如果originalCollections.synchronizedMap()返回的对象,那么必须original上进行同步才能使所有同步正常工作;由于同步地图在内部的运作方式,使用另一个锁定对象不会起作用。

答案 1 :(得分:1)

首先,如果没有某种外部同步,跨多个线程使用HashMap 永远不会安全。如果您目前正在这样做而且没有遇到运气问题,并且您会在不久的将来看到非常奇怪的错误甚至崩溃。

最简单的选择是使用ConcurrentHashMap,它被设计为同时由多个线程安全使用。然后,您可以安全地将地图复制到另一个地图中。

正如Ted Hopp所提到的,使用synchronized块是一种潜在的替代方案,但如果操作不正确,则更容易出错。

另请注意,即使您未在多个线程中使用ConcurrentModificationException,也可以获得HashMap。例如:

for (K key : map.keySet()) {
  map.remove(key);
}

会导致ConcurrentModificationException,因为地图已被修改&#34;同时&#34;试图迭代其内容。因此,仅仅看到CME并不意味着您需要一个线程安全的解决方案,您可能只需要更改您修改集合的方式:

Set<K> keysSnapshot = new HashSet<>(map.keySet());
for (K key : keysSnapshot) {
  map.remove(key);
}