1.关于ConcurrentModificationException和迭代器读写(ArrayList)
a) foreach语法底层其实是使用了iterator。
b) ArrayList在remove/add时会修改一个变量modCount。
c) ArrayList的迭代器是其一个内部类,在创建这个迭代器对象时,它保留了当时的modCount的值,在调用迭代器方法时,会先检测ArrayList.modCount和快照是否相同如果不相同则抛出ConcurrentModificationException。
d) ArrayList的set方法不会修改modCount,所以在迭代器迭代时可以调用set
e) ArrayList的迭代器的remove/add方法内部是调用ArrayList的remove/add,同时更新了自己的modCount快照,所以迭代器修改会造成其他迭代器的ConcurrentModificationException
f)所以for(int i = 0; i < size; i++)不会造成ConcurrentModificationException
2.关于锁和读写(CopyOnWriteArrayList)
a) 所有读的方法和ArrayList没区别,都是直接从源数组里直接随机读取
b) 所有修改的方法add/remove/set/clear共享一把lock
c) add/remove/set都是基于Arrays.copyOf(),产生一个新数组,再将源数组array指向新的数组对象
e) 没有modCount
d) 为什么加写锁了还要复制 -> 为什么写锁要和读锁互斥 -> 64位long型对于32位JVM要写两次,是不保证原子性的,这就可能读到只写了一半的long型(虽然现在虚拟机都实现的long/double的原子性操作,但是jvm规范并没有要求)
f) 所以可以认为CopyOnWriteArrayList是用写时复制代替了读锁,把读的复杂度移到了写时,所以适合读多写少的业务
d) addIfAbsent() 如果没有则添加,CopyOnWriteArraySet内部其实是CopyOnWriteArrayList,add方法调用了CopyOnWriteArrayList#addIfAbsent
3.关于迭代器和UnsupportedOperationException(CopyOnWriteArrayList)
a) CopyOnWriteArrayList的迭代器是其一个内部类,在创建这个迭代器对象时,他保留了当时的源数组,迭代是基于当时快照的,所以对CopyOnWriteArrayList的迭代可能是旧的数据
b) 迭代器代表的是一个过时的数组,所以对过时数组的修改是没有意义的,所以迭代器的修改方法直接抛出UnsupportedOperationException
c) 因为没有modCount所以foreach迭代时可以随便修改list,但是要忍受迭代的过期数据
4.关于subList
a) 对subList的读写其实都是委托源List,所以subList可以看成对index的附加约束
b) CopyOnWriteArrayList的subList是其一个内部类,在创建subList对象时,保留了源list当时的内部array的引用,在之后调用subList的方法时,会校验list的array是否改变如果改变则抛出CopyOnWriteArrayList,而通过subList修改源list后,subList会更新保留的array引用,类似ArrayList的迭代器修改
c) ArrayList的subList是其一个内部类,行为都相似,不过他是通过modCount来做同步校验的,和ArrayList.Iterator基本相同
5.关于扩容
a) CopyOnWriteArrayList在修改时产生新的、大小正好的数组,所以没有扩容问题
b) ArrayList当array剩余空间不足时进行扩容,扩容后的容量是原来的1.5倍,不超过Integer.MAX_VALUE,没有loadfactor这一说
6.关于System.arraycopy和Arrays.copyOf
a) 关于数组的操作上是靠这两个
System.arraycopy(fromArr, fromIndex, toArr, beginIndex, len)
add(int index, Object element):
System.arraycopy(elementData, index, elementData, index + 1, size - index)
elementData[index] = element
remove(int index):
System.arraycopy(elementData, index+1, elementData, index, size - index - 1)
elementData[--size] = null
b)Arrays.copyOf()其实内部是new了一个新的数组,并调用System.arraycopy()把数据写入新数组再返回