本文内容如有错误、不足之处,欢迎技术爱好者们一同探讨,在本文下面讨论区留言,感谢。
简述
Java 中的 CopyOnWriteArrayList 是 List 接口的线程安全实现。在 Java 1.5 和 Collections 框架的一部分中添加了 CopyOnWriteArrayList。在多线程程序中,当开发人员希望以线程安全的方式遍历列表而无需显式同步时,CopyOnWriteArrayList 非常有用。
它是ArrayList的增强版本,其中所有修改(添加,更新,删除等)都通过创建新副本来实现。
继承关系
下图是它的实现关系图:
功能
- CopyOnWriteArrayList 类实现List并继承 RandomAccess 接口,因此提供 ArrayList 类中可用的所有功能。
- 使用 CopyOnWriteArrayList 进行更新操作的成本很高,因为每个迭代器都会创建基础数组的克隆副本,并为其添加/更新元素。
- 它是 ArrayList 的线程安全版本。每个访问列表的线程在初始化此列表的迭代器时都会看到自己创建的快照版本。
- 因为它在创建迭代器时获取基础数组的快照,所以它不会抛出 ConcurrentModificationException。
- 不支持对迭代器的操作(删除,更新和添加),执行这些方法将抛出 UnsupportedOperationException。
- CopyOnWriteArrayList 是同步List的并发替代,当迭代的次数超过一定次数时,CopyOnWriteArrayList 可以提供更好的并发性。
- 它允许重复的元素和异构对象(使用泛型来获取编译时错误)。
- 因为它每次创建迭代器时都会创建一个新的数组副本,所以性能比ArrayList 慢。
示例
import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;
/**
*
* Java program to demonstrate What is CopyOnWriteArrayList in Java,
* CopyOnWriteArrayList 的 Iterator 不支持添加,删除,修改操作。
*/
public class CopyOnWriteArrayListExample{
public static void main(String args[]) {
CopyOnWriteArrayList<String> threadSafeList = new CopyOnWriteArrayList<String>();
threadSafeList.add("Java");
threadSafeList.add("J2EE");
threadSafeList.add("Collection");
//add, remove operator 不被 CopyOnWriteArrayList iterator 支持
Iterator<String> failSafeIterator = threadSafeList.iterator();
while(failSafeIterator.hasNext()){
System.out.printf("Read from CopyOnWriteArrayList : %s %n", failSafeIterator.next());
// failSafeIterator.remove(); //不支持的操作,抛出 java.lang.UnsupportedOperationException 异常信息栈。
}
}
}
输出结果:
Read from CopyOnWriteArrayList : Java
Read from CopyOnWriteArrayList : J2EE
Read from CopyOnWriteArrayList : Collection
插入时迭代
假设我们正在创建一个存储整数的 CopyOnWriteArrayList 实例:
CopyOnWriteArrayList<Integer> numbers = new CopyOnWriteArrayList<>(new Integer[]{1, 3, 5, 8});
接下来,我们要遍历该数组,因此我们要创建一个 Iterator 实例:
Iterator<Integer> iterator = numbers.iterator();
创建迭代器后,将一个新元素添加到数字列表中:
numbers.add(10);
请记住,当为 CopyOnWriteArrayList 创建迭代器时,在调用 iterator() 时,将获得列表中数据的不可变快照。
因此,在进行迭代时,我们不会在迭代中看到数字10:
List<Integer> result = new LinkedList<>();
iterator.forEachRemaining(result::add);
assertThat(result).containsOnly(1, 3, 5, 8);
使用新创建的Iterator进行的后续迭代还将返回添加的数字10:
Iterator<Integer> iterator2 = numbers.iterator();
List<Integer> result2 = new LinkedList<>();
iterator2.forEachRemaining(result2::add);
assertThat(result2).containsOnly(1, 3, 5, 8, 10);
以线程安全的方式对其进行迭代,而其他线程可以继续从中插入或删除元素。
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.*;
class ConcurrentDemo extends Thread {
static CopyOnWriteArrayList l = new CopyOnWriteArrayList();
public void run()
{
// 子线程添加一个元素到集合中
l.add("D");
}
public static void main(String[] args)
throws InterruptedException
{
l.add("A");
l.add("B");
l.add("c");
// 创建一个子线程进行操作
ConcurrentDemo t = new ConcurrentDemo();
// 直接调用资源类中的run方法
t.run();
Thread.sleep(1000);
// 获得集合中的例子
Iterator itr = l.iterator();
while (itr.hasNext()) {
String s = (String)itr.next();
System.out.println(s);
Thread.sleep(1000);
}
System.out.println(l);
}
}
结语
简而言之,如果您主要需要遍历列表而不进行修改,使用 CopyOnWriteArrayList。
参考资料
CopyOnWriteArrayList in java(Java中的CopyOnWriteArrayList)
Guide to CopyOnWriteArrayList(CopyOnWriteArrayList指南)
What is CopyOnWriteArrayList in Java - Example Tutorial(什么是Java中的CopyOnWriteArrayList-示例教程)
CopyOnWriteArrayList in java(Java中的CopyOnWriteArrayList)
Java CopyOnWriteArrayList class(Java CopyOnWriteArrayList类)