Java中的ArrayList与CopyOnWriteArrayList
ArrayList是Java版本1.2中的一部分,在Java 5中,CopyOnWriteArrayList作为ArrayList的线程安全变体在Java 5中添加。在本文中,我们将看到Java中ArrayList和CopyOnWriteArrayList之间的区别。
CopyOnWriteArrayList与Java中的ArrayList
1线程安全性:
CopyOnWriteArrayList是线程安全的。 CopyOnWriteArrayList中的线程安全性是通过为所有可变操作(添加,设置等)制作基础数组的新副本来实现的。
Java中的ArrayList不是线程安全的。
2外部同步:
CopyOnWriteArrayList已经是线程安全的,因此不需要外部同步。
可以使用Collections.synchronizedList()方法从外部同步ArrayList,该方法返回由指定List支持的同步List。在这篇文章中阅读有关同步ArrayList的更多信息如何在Java中同步ArrayList
3 Iterator故障快速或者故障安全:
CopyOnWriteArrayList返回的迭代器是故障安全的,并且保证该迭代器不会抛出ConcurrentModificationException。即使在迭代期间在CopyOnWriteArrayList上调用了任何可变操作,该数组也不会在迭代器的生存期内发生变化,这将导致创建基础数组的新副本,因此不会发生干扰。
ArrayList的iterator和listIterator方法返回的迭代器是快速失败的。如果在创建迭代器之后的任何时间对列表进行结构修改,除非通过迭代器自己的remove或者add方法,否则迭代器将抛出ConcurrentModificationException。
这是一个示例,该示例显示了同时使用ArrayList和CopyOnWriteArrayList的迭代器进行的迭代。
public class ArrayListDemo { public static void main(String[] args) { List<String> nameList = new ArrayList<String>(); // adding elements nameList.add("Adam"); nameList.add("Amy"); nameList.add("Jim"); nameList.add("Leo"); // getting iterator Iterator<String> itr = nameList.iterator(); while(itr.hasNext()){ System.out.println("Name- " + itr.next()); // adding element while iteration nameList.add("Hyman"); } } }
输出:
Name- Adam Exception in thread "main" java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification(Unknown Source) at java.util.ArrayList$Itr.next(Unknown Source) at com.theitroad.ArrayListDemo.main(ArrayListDemo.java:20)
在这里可以看到抛出ConcurrentModificationException,是因为尝试在迭代时将元素添加到ArrayList中。
使用CopyOnWriteArrayList
public class FailSafeDemo { public static void main(String[] args) { List<String> nameList = new CopyOnWriteArrayList<String>(); // adding elements nameList.add("Adam"); nameList.add("Amy"); nameList.add("Jim"); nameList.add("Leo"); // getting iterator Iterator<String> itr = nameList.iterator(); while(itr.hasNext()){ System.out.println("Name- " + itr.next()); // adding element while iteration nameList.add("Hyman"); } } }
输出:
Name- Adam Name- Amy Name- Jim Name- Leo
如我们所见,不会引发ConcurrentModificationException,但是迭代器不会在迭代其他副本时显示新添加的元素。
4性能:
由于底层数组是在每次进行变异操作时都被复制的,因此通常使用CopyOnWriteArrayList会花费太多,但是在遍历操作远远超过变异的情况下使用CopyOnWriteArrayList可能会更有效。
除非必须动态更改数组大小,否则ArrayList不会同步并且不会复制基础数组,因此ArrayList更快。