如何避免HashMap“ConcurrentModificationException”而在并发线程中操作`values()`和`put()`? [英] How to avoid HashMap "ConcurrentModificationException" while manipulating `values()` and `put()` in concurrent threads?

查看:1557
本文介绍了如何避免HashMap“ConcurrentModificationException”而在并发线程中操作`values()`和`put()`?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

代码:



我有一个HashMap

 code> private Map< K,V> map = new HashMap<>(); 

一个方法将通过调用 put )



另一种方法要从其值中提取一组随机元素:

  int size = map.size(); // size> 0 
V [] value_array = map.values()。toArray(new V [size]);
Random rand = new Random();
int start = rand.nextInt(size); int end = rand.nextInt(size);
// return value_array [start .. end - 1]

错误:

p>

我有一个 ConcurrentModificationException 错误:

 在java.util.HashMap $ HashIterator.nextEntry(未知源)
在java.util.HashMap $ ValueIterator.next(未知源)
在java.util.AbstractCollection.toArray (未知来源)

看起来 toArray()方法在一个线程实际上是迭代HashMap和 put()修改在其他线程发生。



<问题:在并发线程中使用HashMap.values().toArray()和HashMap.put()时如何避免ConcurrentModificationException?

直接避免在第二种方法中使用 values()。toArray()也可以。



<你需要提供一些级别的同步,以便调用 put 被阻止,而 toArray 调用正在执行,反之亦然。有三种两种简单方法:


  1. 将您的电话接到 put toArray

  2. 使用 Collections.synchronizedMap()

      private Map< K,V& map = Collections.synchronizedMap(new HashMap<>()); 


  3. 使用 ConcurrentHashMap 而不是 HashMap


编辑:使用 Collections.synchronizedMap 的问题是,一旦调用 values() ,并发保护将消失。此时,调用 put() toArray()可能会同时执行。 A ConcurrentHashMap 有一些类似的问题,但它仍然可以使用。在 <$ c的文档中$ c> ConcurrentHashMap.values()


视图的迭代器是 迭代器,它永远不会抛出 ConcurrentModificationException ,并且保证遍历元素,因为它们在迭代器构建时存在,并且可以(但不能保证)反映构造之后的任何修改。



Code:

I have a HashMap

private Map<K, V> map = new HashMap<>();

One method will put K-V pair into it by calling put(K,V).

The other method wants to extract a set of random elements from its values:

int size = map.size();    // size > 0
V[] value_array = map.values().toArray(new V[size]);
Random rand = new Random();
int start = rand.nextInt(size); int end = rand.nextInt(size);
// return value_array[start .. end - 1]

The two methods are called in two different concurrent threads.


Error:

I got a ConcurrentModificationException error:

at java.util.HashMap$HashIterator.nextEntry(Unknown Source)
at java.util.HashMap$ValueIterator.next(Unknown Source)
at java.util.AbstractCollection.toArray(Unknown Source)

It seems that the toArray() method in one thread is actually iterating over the HashMap and a put() modification in other thread occurs.

Question: How to avoid "ConcurrentModificationException" while using HashMap.values().toArray() and HashMap.put() in concurrent threads?
Directly avoiding using values().toArray() in the second method is also OK.

解决方案

You need to provide some level of synchronization so that the call to put is blocked while the toArray call is executing and vice versa. There are three two simple approaches:

  1. Wrap your calls to put and toArray in synchronized blocks that synchronize on the same lock object (which might be the map itself or some other object).
  2. Turn your map into a synchronized map using Collections.synchronizedMap()

    private Map<K, V> map = Collections.synchronizedMap(new HashMap<>());
    

  3. Use a ConcurrentHashMap instead of a HashMap.

EDIT: The problem with using Collections.synchronizedMap is that once the call to values() returns, the concurrency protection will disappear. At that point, calls to put() and toArray() might execute concurrently. A ConcurrentHashMap has a somewhat similar problem, but it can still be used. From the docs for ConcurrentHashMap.values():

The view's iterator is a "weakly consistent" iterator that will never throw ConcurrentModificationException, and guarantees to traverse elements as they existed upon construction of the iterator, and may (but is not guaranteed to) reflect any modifications subsequent to construction.

这篇关于如何避免HashMap“ConcurrentModificationException”而在并发线程中操作`values()`和`put()`?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆