我有一个场景,我想以一种线程安全的方式将HashMap复制到一个新的HashMap中。我想这样做是为了避免在复制地图时出现任何并发修改异常。
答案 0 :(得分:2)
您需要确保在创建新地图时不会修改原始HashMap。最直接的方法是在原始地图上进行同步:
HashMap<K, V> original = ...
HashMap<K, V> copy;
synchronized (original) {
copy = new HashMap<>(original);
}
如果所有可能修改original
的代码在同一个对象(original
本身上同步,在我的示例代码中,虽然它可以是任何共享对象,但这只能以线程安全的方式工作)。如果original
是Collections.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);
}