异常原因
package com.company;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* @Author you guess
* @Date 2021/1/7 12:33
* @Version 1.0
* @Desc
*/
public class Main26 {
public static void main(String[] args) {
List<String> res1 = new ArrayList<>();
res1.add("1");
res1.add("2");
res1.add("3");
res1.add("4");
// res1.add("5");
// res1.add("6");
// res1.add("7");
// res1.add("8");
// res1.add("9");
System.out.println(res1);//[1, 2, 3, 4]
//死循环
// for (int i = 0; i < res1.size(); i++) {
// res1.add(i + 10 + "");
// }
//
// int size = res1.size();
// for (int i = 0; i < size; i++) {
// res1.add(i + 10 + "");
// }
// System.out.println(res1);//[1, 2, 3, 4, 10, 11, 12, 13]
// for (int i = 0; i < res1.size(); i++) {
// res1.remove(i);
// }
// System.out.println(res1);//[2, 4]
// for (int i = 0; i < res1.size(); i++) {
// if (res1.get(i).equals("1")) {
// res1.remove(i);
// }
// }
// System.out.println(res1);//[2, 3, 4]
Iterator<String> iterator = res1.iterator();
while (iterator.hasNext()) {//ArrayList.Itr.hasNext()
String str = iterator.next();//ArrayList.Itr.next()
if (str.equals("2"))
// res1.remove(str);//ArrayList.remove();Exception in thread "main" java.util.ConcurrentModificationException
iterator.remove();//正常,ArrayList.Itr.remove(),原list的该元素也会删掉
}
System.out.println(res1);//[1, 3, 4]
}
}
复制代码
为何会报异常ConcurrentModificationException?
上述代码只有res1.remove()才是调用的ArrayList自身的代码,res1.remove()执行时会导致modCount加1,但是expectedModCount却没有变化,等到执行iterator.next()时会导致异常!!
如果用iterator.remove()则不报异常!!
ArrayList.java某段:Iterator的方法源码:
/**
* An optimized version of AbstractList.Itr
*/
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;//expectedModCount是在Itr中定义的
Itr() {}
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();//检查
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();//这里会检查
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;//这里有赋值
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
@Override
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
.......
}
final void checkForComodification() {//抛出异常
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
复制代码
ArrayList.java某段:自身的方法源码
/**
* Removes the element at the specified position in this list.
* Shifts any subsequent elements to the left (subtracts one from their
* indices).
*
* @param index the index of the element to be removed
* @return the element that was removed from the list
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E remove(int index) {
rangeCheck(index);
modCount++;//加1,expectedModCount是在Itr中定义的,没有赋值给expectedModCount
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
/**
* Removes the first occurrence of the specified element from this list,
* if it is present. If the list does not contain the element, it is
* unchanged. More formally, removes the element with the lowest index
* <tt>i</tt> such that
* <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>
* (if such an element exists). Returns <tt>true</tt> if this list
* contained the specified element (or equivalently, if this list
* changed as a result of the call).
*
* @param o element to be removed from this list, if present
* @return <tt>true</tt> if this list contained the specified element
*/
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
/*
* Private remove method that skips bounds checking and does not
* return the value removed.
*/
private void fastRemove(int index) {
modCount++;//加1,expectedModCount是在Itr中定义的,没有赋值给expectedModCount
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
}
复制代码
jdk1.8源码 如上。
方法:单线程,使用 iterator.remove();即可,原list的该元素也会删掉
方法:多线程,CopyOnWriteArrayList(不保证数据一致性)
/**
* 原因在于,虽然Vector的方法采用了synchronized进行了同步,但是实际上通过Iterator访问的情况下,每个线程里面返回的是不同的iterator,
* 也即是说expectedModCount是每个线程私有。假若此时有2个线程,线程1在进行遍历,线程2在进行修改,那么很有可能导致线程2修改后导致Vector中的modCount自增了,
* 线程2的expectedModCount也自增了,但是线程1的expectedModCount没有自增,此时线程1遍历时就会出现expectedModCount不等于modCount的情况了。
* <p>
* expectedModCount是线程私有的,modCount是线程共享的;
* thread2使expectedModCount、modCount都加1后,但是thread1的modCount还是原值,所以抛出异常
*
* @param args
*/
public static void main(String[] args) {
//Vector<Integer> list = new Vector<Integer>(); 也报异常ConcurrentModificationException
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
Thread thread1 = new Thread() {
public void run() {
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {
Integer integer = iterator.next();
System.out.println(integer);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
;
};
Thread thread2 = new Thread() {
public void run() {
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {
Integer integer = iterator.next();
if (integer == 2)
iterator.remove();
}
}
;
};
thread1.start();
thread2.start();
}
// 1
// Exception in thread "Thread-0" java.util.ConcurrentModificationException
// at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
// at java.util.ArrayList$Itr.next(ArrayList.java:859)
// at com.company.Main27$1.run(Main27.java:25)
public static void main(String[] args) {
CopyOnWriteArrayList<Integer> list = new CopyOnWriteArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
Thread thread1 = new Thread() {
public void run() {
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {
Integer integer = iterator.next();
System.out.println(integer);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
;
};
Thread thread2 = new Thread() {
public void run() {
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {
Integer integer = iterator.next();
if (integer == 2)
iterator.remove();
}
}
;
};
thread1.start();
thread2.start();
}
// Exception in thread "Thread-1" java.lang.UnsupportedOperationException
// at java.util.concurrent.CopyOnWriteArrayList$COWIterator.remove(CopyOnWriteArrayList.java:1178)
// at com.company.Main27$2.run(Main27.java:92)
// 1
// 2
// 3
// 4
// 5
复制代码
end
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END