List : 在多线程操作List的时候,在一个线程里面add东西,list实际上的大小跟预计是不一样的
public void demo1() { List<String> list = new ArrayList<>(); Random random = new Random(); for (int i = 0; i < 10; i++) { new Thread(()->{ list.add(String.valueOf(random.nextInt())); System.out.println(list); }).start(); } //出现异常:Exception in thread "Thread-0" java.util.ConcurrentModificationException }
解决方法:
- - 使用Vector类,Vector线程安全,缺点效率不高。
- - 使用Collections.synchronizedList()方法,参数为一个List对象
- - 使用CopyOnWriteArrayList类
CopyOnWriteArrayList的底层 add() 方法的实现:
原理:写时进行复制
public boolean add(E e) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray();//返回object数组 int len = elements.length; //得到原数组的长度 Object[] newElements = Arrays.copyOf(elements, len + 1); newElements[len] = e;//进行下标赋值 setArray(newElements);//进行数组赋值 return true; } finally { lock.unlock(); } }
//setArray的源码
final void setArray(Object[] a) {
array = a;
}
remove方法:
public E remove(int index) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); int len = elements.length; E oldValue = get(elements, index); int numMoved = len - index - 1; //得到数组的整体之后的长度 if (numMoved == 0) setArray(Arrays.copyOf(elements, len - 1)); else { Object[] newElements = new Object[len - 1]; System.arraycopy(elements, 0, newElements, 0, index); System.arraycopy(elements, index + 1, newElements, index, numMoved); setArray(newElements); } return oldValue; } finally { lock.unlock(); } }