?
注意,ArrayList实现不是同步的。如果多个线程同时访问一个 ArrayList 实例,而其中至少一个线程从结构上修改了列表,那么它必须 保持外部同步。(结构上的修改是指任何添加或删除一个或多个元素的操作,或者显式调整底层数组的大小;仅仅设置元素的值不是结构上的修改。)这一般通过对自然封装该列表的对象进行同步操作来完成。如果不存在这样的对象,则应该使用Collections.synchronizedList
方法将该列表“包装”起来。这最好在创建时完成,以防止意外对列表进行不同步的访问:
List list = Collections.synchronizedList(new ArrayList(...));
此类的 iterator 和 listIterator 方法返回的迭代器是快速失败的:在创建迭代器之后,除非通过迭代器自身的remove 或 add 方法从结构上对列表进行修改,否则在任何时间以任何方式对列表进行修改,迭代器都会抛出 ConcurrentModificationException
。因此,面对并发的修改,迭代器很快就会完全失败,而不是冒着在将来某个不确定时间发生任意不确定行为的风险。
注意,迭代器的快速失败行为无法得到保证,因为一般来说,不可能对是否出现不同步并发修改做出任何硬性保证。快速失败迭代器会尽最大努力抛出 ConcurrentModificationException。因此,为提高这类迭代器的正确性而编写一个依赖于此异常的程序是错误的做法:迭代器的快速失败行为应该仅用于检测 bug。
?
?测试
package my.test; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** *@author E-mail: xyylchq@163.com *@version 创建时间:2012-8-15下午02:11:03 *类说明 */ public class ConcurrentModificationExceptionTest { public static void main(String[] args) { final ArrayList<Object> list = new ArrayList<Object>(); for(int i = 0; i < 5; i ++) { list.add(i); } List<Object> list2 = (List)list.clone(); // list.clear(); // System.out.println(list2.size()); Runnable run = new Runnable( ) { @Override public void run() { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("3秒过后给list赋值"); //添加测试 list.add("sd"); list.add("sd"); //删除测试 // list.clear(); } }; new Thread(run).start(); Iterator<Object> iterator = list.iterator(); // for(int i = 0; i < list.size(); i++) { while(iterator.hasNext()) { System.out.println(iterator.next()); // System.out.println(list.get(i)); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
?
?
解决方法:
1.?? 使用 Collections.synchronizedList
方法将该列表“包装”起来。
2. ? 将要创建的ArrayList创建一个副本,clone出一个副本。