List 接口的大小可变数组的实现。*内部默认每次扩容0.5倍。实现了所有可选列表操作,并允许包括 null 在内的所有元素。除了实现 List 接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小。void ensureCapacity(int minCapacity),来操作底层数组大小。(此类大致上等同于 Vector 类,除了此类是不同步的。)
在该实现类中:modCount会增加的方法有:void trimToSize(); void ensureExplicitCapacity(int minCapacity); E remove(int index); void fastRemove(int index);void clear(); void removeRange(int fromIndex, int toIndex);
注意,此实现不是同步的。如果多个线程同时访问一个 ArrayList 实例,而其中至少一个线程从结构上修改了列表,那么它必须 保持外部同步。当不保证外部同步时,如下列测试代码所示,会抛出并发修改异常。
private static List<Integer> a = new ArrayList<Integer>();
public static void main(String[] args) {
for (int i = 1; i < 100; i++) {
a.add(i);
}
Thread t1 = new Thread() {
public void run() {
Iterator<Integer> it1 = a.iterator();
while (it1.hasNext()) {
System.out.println(it1.next());
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
Thread t2 = new Thread() {
public void run() {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for (int i = 1; i < 10; i++) {
a.remove(10 * i);
}
}
};
t1.start();
t2.start();
}
JAVA提供了一个类以检测BUG:Collections.synchronizedList(new ArrayList(...));//此类的 iterator 和 listIterator 方法返回的迭代器是快速失败的:在创建迭代器之后,除非通过迭代器自身的 remove 或 add 方法从结构上对列表进行修改,否则在任何时间以任何方式对列表进行修改,迭代器都会抛出 ConcurrentModificationException
。因此,面对并发的修改,迭代器很快就会完全失败,而不是冒着在将来某个不确定时间发生任意不确定行为的风险。注意,迭代器的快速失败行为无法得到保证,因为一般来说,不可能对是否出现不同步并发修改做出任何硬性保证。快速失败迭代器会尽最大努力抛出 ConcurrentModificationException。因此,为提高这类迭代器的正确性而编写一个依赖于此异常的程序是错误的做法:迭代器的快速失败行为应该仅用于检测 bug。
为了使变长数组可以适用于要求线程安全的情况。使用CopyOnWriteArrayList<E>类。
CopyOnWriterArrayList所代表的核心概念就是:任何对array在结构上有所改变的操作(add、remove、clear等),CopyOnWriterArrayList都会copy现有的数据,再在copy的数据上修改,这样就不会影响COWIterator中的数据了,修改完成之后改变原有数据的引用即可。同时这样造成的代价就是产生大量的对象,同时数组的copy也是相当有损耗的。
参考文献:
[1] Java提高篇(三四)-----fail-fast机制 https://www.cnblogs.com/chenssy/p/3870107.html