`
george.gu
  • 浏览: 73293 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

java.util.ConcurrentModificationException

阅读更多

Where ConcurrentModificationException raised

Case 1: update value Entries during traverse Map in same Thread

java.util.ConcurrentModificationException will be raised in following java code:

 

		Map<String, String> pendingCorrelations = new Hashtable<String, String>();
		pendingCorrelations.put("a", "a1");
		pendingCorrelations.put("b", "b1");
		pendingCorrelations.put("c", "c1");
		pendingCorrelations.put("d", "d1");
		pendingCorrelations.put("e", "e1");
		Set<String> keys = pendingCorrelations.keySet();
		for (String key : keys) { // Here raise ConcurrentModificationException after a is removed.
			if (key.equalsIgnoreCase("a")) {
				 pendingCorrelations.remove(key); 
			}
		}

Exception:

 

java.util.ConcurrentModificationException
	at java.util.Hashtable$Enumerator.next(Hashtable.java:1031)

 

Case 2: This exception could happen in case many simultaneouse threads manipulate same value Object.

 

Why ConcurrentModificationException raised?

Here we focous on two points:

  1. How Java analyze for() element?
  2. What happened after Hashtable.remove(Object)?

We can image JDK will analyze for() as following:

 

	for(String key=Hashtable$Enumerator.next();Hashtable$Enumerator.hasMoreElements();){
		pendingCorrelations.remove(key);
	}

 

An interesting source code to understand well for() elements:

 

		Map<String, String> pendingCorrelationsMap = new HashMap<String, String>();
		pendingCorrelationsMap.put("c", "c1");
		pendingCorrelationsMap.put("b", "b1");
		pendingCorrelationsMap.put("d", "b1");
		pendingCorrelationsMap.put("a", "a1");

		for (String key : pendingCorrelationsMap.keySet()) {
			if (key.equalsIgnoreCase("a")) { // won't cause ConcurrentModificationException
				pendingCorrelationsMap.remove(key);
			}
		}


		for (String key : pendingCorrelationsMap.keySet()) {
			if (key.equalsIgnoreCase("c")) { // will cause ConcurrentModificationException
				pendingCorrelationsMap.remove(key);
			}
		}
 

 

java.util.Hashtable

 

    /**
     * The number of times this Hashtable has been structurally modified
     * Structural modifications are those that change the number of entries in
     * the Hashtable or otherwise modify its internal structure (e.g.,
     * rehash).  This field is used to make iterators on Collection-views of
     * the Hashtable fail-fast.  (See ConcurrentModificationException).
     */
    private transient int modCount = 0;



	/**
	 * The modCount value that the iterator believes that the backing
	 * Hashtable should have.  If this expectation is violated, the iterator
	 * has detected concurrent modification.
	 */
	protected int expectedModCount = modCount;


    /**
     * Removes the key (and its corresponding value) from this
     * hashtable. This method does nothing if the key is not in the hashtable.
     *
     * @param   key   the key that needs to be removed
     * @return  the value to which the key had been mapped in this hashtable,
     *          or <code>null</code> if the key did not have a mapping
     * @throws  NullPointerException  if the key is <code>null</code>
     */
    public synchronized V remove(Object key) {
	Entry tab[] = table;
	int hash = key.hashCode();
	int index = (hash & 0x7FFFFFFF) % tab.length;
	for (Entry<K,V> e = tab[index], prev = null ; e != null ; prev = e, e = e.next) {
	    if ((e.hash == hash) && e.key.equals(key)) {
		modCount++;  // Only modCount updated within Hashtable.remove(Object)
		if (prev != null) {
		    prev.next = e.next;
		} else {
		    tab[index] = e.next;
		}
		count--;
		V oldValue = e.value;
		e.value = null;
		return oldValue;
	    }
	}
	return null;
    }

We can see that if any Object removed by invode Hashtable.remove(Object), only "modCount++" invoked (not expectedModCount). 

 

java.util.Hashtable$Enumerator<T>

Hashtable$Enumberator<T>

 

    /**
     * A hashtable enumerator class.  This class implements both the
     * Enumeration and Iterator interfaces, but individual instances
     * can be created with the Iterator methods disabled.  This is necessary
     * to avoid unintentionally increasing the capabilities granted a user
     * by passing an Enumeration.
     */
    private class Enumerator<T> implements Enumeration<T>, Iterator<T> {
        ...
	public T next() {
	    if (modCount != expectedModCount)
		throw new ConcurrentModificationException();
	    return nextElement();
	}

	public void remove() {
	    if (!iterator)
		throw new UnsupportedOperationException();
	    if (lastReturned == null)
		throw new IllegalStateException("Hashtable Enumerator");
	    if (modCount != expectedModCount)
		throw new ConcurrentModificationException();

	    synchronized(Hashtable.this) {
		Entry[] tab = Hashtable.this.table;
		int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length;

		for (Entry<K,V> e = tab[index], prev = null; e != null;
		     prev = e, e = e.next) {
		    if (e == lastReturned) {
			modCount++; //both modCount and expectedModCount will be updated simultanously
			expectedModCount++;
			if (prev == null)
			    tab[index] = e.next;
			else
			    prev.next = e.next;
			count--;
			lastReturned = null;
			return;
		    }
		}
		throw new ConcurrentModificationException();
	    }
	}
        ...
}

 

 Hashtable$Enumberator.next() will check (modCount != expectedModCount) to fast fail. Here can see how "java.util.ConcurrentModificationException" raised.

 

Solutions

Solution 1: Update(Remove) java collections through Iterator

As we list in prior java source code, we can see both "modCount" and "expectedCount" will be udpated simultanousely in Hashtable$Enumberator which will be return when calling Hashtable.interator(). 

So we can remove elements as following without ConcurrentModificationException:

 

Iterator iter = Collections.iterator();
while(iter.hasNext()) {
        iter.next(); // Iterator.next() must be called before calling remove()
        iter.remove(); // should be called once and only once
}

Note:

 

  1. Here "Collections" is only a symbol of set of objects it is not "java.util.Collection".
  2. We can only invoke remove through Iterator. (because there is no other udpate operation API.)

 Solution 2: Remove Objects from Collections outof Traverse Collections.

 

		Map<String, String> pendingCorrelations = new Hashtable<String, String>();
		pendingCorrelations.put("a", "a1");
		pendingCorrelations.put("b", "b1");
		pendingCorrelations.put("c", "c1");
		pendingCorrelations.put("d", "d1");
		pendingCorrelations.put("e", "e1");
		Set<String> keys = pendingCorrelations.keySet();
		List<String> tobeRemvoed = new ArrayList<String>();
		for (String key : keys) {
			if (key.equalsIgnoreCase("a")) {
				tobeRemvoed.add(key);
				// pendingCorrelations.remove(key);
			}
		}

		assertEquals(5, pendingCorrelations.size());
		for (String str : tobeRemvoed) {
			pendingCorrelations.remove(str);
		}
		assertEquals(4, pendingCorrelations.size());
 

 

 

0
0
分享到:
评论

相关推荐

    java.util.ConcurrentModificationException 异常问题详解1

    Java.util.ConcurrentModificationException 异常问题详解 ConcurrentModificationException 异常是 Java 中一个常见的异常,它发生在 Iterator 遍历集合时,集合同时被修改引起的异常。在 Java 中,集合类如 ...

    出现java.util.ConcurrentModificationException 问题及解决办法

    在Java编程中,`java.util.ConcurrentModificationException` 是一个常见的运行时异常,通常发生在尝试并发修改集合时。这个异常的产生是由于集合类(如HashMap)的非线程安全特性,当你在一个线程中使用迭代器遍历...

    java.util.ConcurrentModificationException 解决方法

    `java.util.ConcurrentModificationException` 是一个在 Java 中常见的运行时异常,它通常发生在多线程环境中,当一个线程正在遍历一个集合(如 `ArrayList`, `HashMap` 等),而另一个线程同时尝试修改这个集合时。...

    java.util.concurrent系列文章(1)

    ### Java.util.concurrent 系列文章知识点总结 #### 一、引言 随着多核处理器的普及,多线程编程已成为现代软件开发中的一个重要组成部分。Java 5 引入了 `java.util.concurrent` 包,该包提供了丰富的 API 来简化...

    java 集合并发操作出现的异常ConcurrentModificationException

    在Java编程中,`ConcurrentModificationException`是一个常见的运行时异常,主要出现在多线程环境下对集合类(如List、Set、Map等)进行并发修改时。然而,这个异常不仅限于多线程环境,即使在单线程中,如果在遍历...

    Java语言的Util类详细介绍

    Java语言的Util类详细介绍 Java语言的Util类是Java开发中非常重要的一部分,它提供了一系列的类来实现基本的数据结构,如线性表、链表等。这些类均在java.util包中。 Collection接口是Java中最基本的集合接口,一...

    spring-data-mongodb-test:在Collections.synchronizedList或Collections.synchronizedSet上测试spring数据mongodb ConcurrentModificationException

    Spring数据mongodb测试 在Collections.synchronizedList或Collections.synchronizedSet上测试spring数据mongodb ConcurrentModificationException

    java8集合源码-zinc-ConcurrentModificationException:锌并发修改异常

    java.util.ConcurrentModificationException: mutation occurred during iteration [error] scala.collection.mutable.MutationTracker$.checkMutations(MutationTracker.scala:43) [error] scala.collection....

    JAVA.BUG模式详解

    使用`synchronized`关键字、`volatile`变量、`java.util.concurrent`包中的工具类等可以有效地管理并发。 四、内存泄漏 Java中的内存泄漏并不像C++那样直接导致资源耗尽,但过度持有对象引用会导致垃圾收集器无法...

    使用Iterator接口遍历集合元素

    否则将会引发 java.util.ConcurrentModificationException 异常。 3. Iterator 迭代器采用的是快速失败(fail-fast)机制,一旦在迭代过程中检测到该集合已经被修改(通常是程序中其它线程修改),程序立即引发 ...

    jdk 1.6 API 中文版帮助文档

    - `java.util.Iterator`的改进:支持`remove()`操作,避免抛出`ConcurrentModificationException`。 ### 4. 性能优化 JDK 1.6对编译器和垃圾收集器进行了优化,提高了运行效率,例如: - **Server VM的改进**: ...

    collecter集合总结

    需要注意的是,在迭代的过程中不能对集合中元素进行修改,否则将产生 java.util.ConcurrentModificationException。 选择集合 在实际开发中,选择合适的集合是非常重要的。以下是一些选择集合的建议: * 如果需要...

    迭代大师的修炼之道:Java中Iterator与增强for循环的深度解析

    import java.util.ArrayList; import java.util.Iterator; public class IteratorExample { public static void main(String[] args) { ArrayList&lt;String&gt; names = new ArrayList(); names.add("Ada Lovelace");...

    Java多线程安全集合

    Java的`java.util.concurrent`包提供了更为高效且专门设计用于并发操作的集合。比如: - `ConcurrentHashMap`:线程安全的哈希映射,比`synchronized Map`性能更好,因为它允许不同部分独立加锁,减少了锁竞争。 ...

    多线程中使用Java集合类.doc

    4. 如果需要更复杂的并发控制,可以使用`java.util.concurrent.locks`包下的Lock接口及其实现,如ReentrantLock,配合`tryLock()`方法进行细粒度的锁控制。 总的来说,处理多线程环境中的Java集合类时,开发者需要...

    Java中CopyOnWriteArrayList的使用

    java中,List在遍历的时候,如果被修改了会抛出java.util.ConcurrentModificationException错误。  看如下代码: import java.util.ArrayList; import java.util.List; public class Resource3 { public ...

    Java源码分析:深入探讨Iterator模式

    在Java编程语言中,集合框架(`java.util`包)提供了多种容器类来存储对象,如`List`、`Set`和`Map`等。为了遍历这些容器中的元素,Java引入了迭代器模式(Iterator Pattern),这是一种常用的设计模式,它提供了一...

    高并发常见面试题(深入底层).docx

    当多个线程同时调用`add`方法时,可能会抛出`java.util.ConcurrentModificationException`异常。 **4.2 解决方案** - 使用`Vector`类代替`ArrayList`,因为`Vector`的所有公共方法都进行了同步处理,但这种方法降低...

Global site tag (gtag.js) - Google Analytics