在java中学习CopyOnWriteArrayList的教程与实例

234 阅读2分钟

CopyOnWriteArrayList是java.util.Concurrent包中的一个类。这是在Java 5中引入的,作为java并发API变化的一部分。它被用于多线程的安全应用程序。这是ArrayList的一个并发版本。

为什么引入CopyOnWriteArrayList?

ArrayList是java集合中的列表实现,ArrayList不是线程安全的,不能用于多线程应用。见下面的例子 创建ArrayList对象。使用Iterate方法对每个元素进行遍历。

import java.util.ArrayList;  
import java.util.Iterator;  
import java.util.List;  
  
public class ArrayListDemo {  
 public static void main(String args[]) {  
  List names = new ArrayList<>();  
  names.add("one");  
  names.add("two");  
  names.add("three");  
  names.add("four");  
  Iterator it = names.iterator();  
  while (it.hasNext()) {  
   String value = it.next();  
   System.out.println(value);  
   if (value.equals("three")) {  
    names.remove("four");  
    names.add("five");  
    names.add("four");  
   }  
  }  
  System.out.println(names.size());  
  
 }  
}

在迭代过程中,当一个元素在iterator()中被移除时,iterator.next()方法会抛出ConcurrentModifiedException:

one  
two  
three  
Exception in thread "main" java.util.ConcurrentModificationException  
 at java.util.ArrayList$Itr.checkForComodification(Unknown Source)  
 at java.util.ArrayList$Itr.next(Unknown Source)  
 at ArrayListDemo.main(ArrayListDemo.java:14)  

ArrayList是快速失败的,这意味着如果列表被添加或删除,如果任何线程正在进行迭代,Next()方法会抛出ConcurrentModifiedException ArrayList在多线程的应用程序中不会像预期那样工作。

CopyOnWriteArrayList对象如何工作?

多线程应用程序中的CopyOnWriteArrayList是一个与应用程序中的ArrayList相同或相似的类,当第一次对该列表调用iterator()时,它会创建一个列表的快照副本。它将为每一个修改(添加,设置删除)操作创建一个克隆版的数组列表,并且同步将由JVM完成。从性能上讲,它为每一个修改操作创建重复的拷贝,因此成本很高。

例子

import java.util.Iterator;  
import java.util.List;  
import java.util.concurrent.CopyOnWriteArrayList;  
  
public class ListDemo {  
 public static void main(String args[]) {  
  List myList = new CopyOnWriteArrayList();  
  myList.add("ten");  
  myList.add("nine");  
  myList.add("eight");  
  myList.add("seven");  
  myList.add("six");  
  Iterator it = myList.iterator();  
  while (it.hasNext()) {  
   String element = it.next();  
   System.out.println(element);  
   if (element.equals("eight")) {  
    myList.remove("seven");  
    myList.add("five");  
    myList.add("four");  
   }  
  }  
  System.out.println(myList.size());  
  
 }  
}

优点

  • 当列表被其他线程修改/更新时,可以安全地迭代列表。
  • 它最适合于读操作
  • 适用于少数修改和许多读操作

缺点

如果你经常添加元素,这将是昂贵的:

  • 在迭代过程中使用同步块来锁定
  • 使用CopyOnWriteArrayList来避免这种异常。