Java中的ArrayList与CopyOnWriteArrayList

时间:2020-01-09 10:35:09  来源:igfitidea点击:

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更快。