第一种 - Iterator(迭代器)
Iterator<String> iterator = list.iterator();
while(iter.hasNext())
{
iter.next();
}
这种方式在循环执行过程中会进行数据锁定,性能稍差。
同时,如果你想在进行遍历的过程中,移除 List 中的某个元素,只能调用 iterator.remove 方法,而不能使用 list.remove () 方法,否则会抛出并发修改异常(java.util.ConcurrentModificationException)。
第二种 - foreach
for(String tmp:list)
{
//do something
}
foreach 只是 Java 提供的语法糖,内部调用 Iterator(第一种),换汤不换药,因此比 Iterator 稍慢。
第三种 - get (i)
int listSize = list.size();
for (int i = 0; i < listSize; i++) {
list.get(i);
}
内部不锁定,效率最高,但是当写多线程时要考虑并发操作的问题。
Iterator(迭代器)的使用 - Fail fast 问题
前面我们提到了,如果你想在使用 Iterator(迭代器)进行遍历的过程中,移除 List 中的某个元素,只能调用 iterator.remove 方法,而不能调用 list.remove () 方法,否则一定会抛出并发修改异常(java.util.ConcurrentModificationException)。
注意,当这个异常被抛出时,并不意味着这个 list 一定正在被多个线程同时使用,而在同一个线程中既一边遍历 list,一边调用 list.remove () 方法,也会抛出 ConcurrentModificationException。
解决办法
可以使用 CopyOnWriteArrayList 来替换 ArrayList。
CopyOnWriteArrayList 为何物?
CopyOnWriteArrayList 是 ArrayList 的一个线程安全的变体,其中所有可变操作(add、set 等等)都是通过对底层数组进行一次新的复制来实现的。
因此,该类产生的开销比较大,但是在两种情况下,它非常适合使用:
- 在不能或不想进行同步遍历,但又需要从并发线程中排除冲突时。
- 当遍历操作的数量大大超过可变操作的数量时。
遇到这两种情况使用 CopyOnWriteArrayList 来替代 ArrayList 再适合不过了。
那么,为什么 CopyOnWriterArrayList 可以替代 ArrayList 呢?
- CopyOnWriterArrayList 的无论是从数据结构、定义都和 ArrayList 一样。它和 ArrayList 一样,同样是实现 List 接口,底层使用数组实现。在方法上也包含 add、remove、clear、iterator 等方法。
- CopyOnWriterArrayList 根本就不会产生 ConcurrentModificationException 异常,也就是它使用迭代器完全不会产生 fail-fast 机制。
Reference
- Java 提高篇(三四)—–fail-fast 机制 - https://www.cnblogs.com/chenssy/p/3870107.html