Java 中的 CopyOnWriteArrayList
CopyOnWriteArrayList 类是在 JDK 1.5 中引入的,它实现了 List 接口。它是 ArrayList 的增强版本,其中所有修改(添加、设置、删除等)都是通过制作新副本来实现的。它位于 java.util.concurrent 包中。它是为在并发环境中使用而创建的数据结构。
以下是关于 CopyOnWriteArrayList 的几点:
- 顾名思义,CopyOnWriteArrayList 会创建底层 ArrayList 的克隆副本,对于某个时间点的每次更新作,两者都会自动同步,这由 JVM 负责。因此,对执行读取作的线程没有影响。
- 使用成本很高,因为对于每个更新作,都会创建一个克隆的副本。因此,如果我们频繁的作是读取作,则 CopyOnWriteArrayList 是最佳选择。
- 带下划线的数据结构是可增长的数组。
- 它是 ArrayList 的线程安全版本。
- 保留插入,允许重复、空和异构对象。
- CopyOnWriteArrayList 的主要要点是 CopyOnWriteArrayList 的迭代器无法执行删除作,否则我们会收到运行时异常 UnsupportedOperationException。 CopyOnWriteArrayList 迭代器上的 add() 和 set() 方法也会引发 UnsupportedOperationException。 此外,CopyOnWriteArrayList 的 Iterator 永远不会抛出 ConcurrentModificationException。
声明:
公共类 CopyOnWriteArrayList 扩展了对象实现 List、RandomAccess、Cloneable、Serializable
此处,E 是此集合中保存的元素类型。
注意:该类实现了 Serializable、Cloneable、Iterable、Collection、List、RandomAccess 接口。
构造 函数:
- CopyOnWriteArrayList():创建一个空列表。
CopyOnWriteArrayList c = new CopyOnWriteArrayList();
- CopyOnWriteArrayList(Collection obj):创建一个包含指定集合元素的列表,这些元素按集合的迭代器返回的顺序排列。
CopyOnWriteArrayList c = new CopyOnWriteArrayList(Collection obj);
- CopyOnWriteArrayList(Object[] obj);:创建一个包含给定数组副本的列表。
CopyOnWriteArrayList c = new CopyOnWriteArrayList(Object[] obj);
例:
// Java program to illustrate
// CopyOnWriteArrayList class
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;public class ConcurrentDemo extends Thread {static CopyOnWriteArrayList<String> l= new CopyOnWriteArrayList<String>();public void run(){// Child thread trying to// add new element in the// Collection objectl.add("D");}public static void main(String[] args)throws InterruptedException{l.add("A");l.add("B");l.add("c");// We create a child thread// that is going to modify// ArrayList l.ConcurrentDemo t = new ConcurrentDemo();t.start();Thread.sleep(1000);// Now we iterate through// the ArrayList and get// exception.Iterator itr = l.iterator();while (itr.hasNext()) {String s = (String)itr.next();System.out.println(s);Thread.sleep(1000);}System.out.println(l);}
}
输出
A
B
c
D
[A, B, c, D]
迭代 CopyOnWriteArrayList: 我们可以使用 iterator() 方法迭代 CopyOnWriteArrayList。需要注意的重要一点是,我们创建的迭代器是原始列表的不可变快照。由于这个属性,我们可以看到 GfG 在第一次迭代时没有打印。
// Java program to illustrate
// CopyOnWriteArrayList class
import java.io.*;
import java.util.*;
import java.util.concurrent.*;class Demo {public static void main(String[] args){CopyOnWriteArrayList<String> list= new CopyOnWriteArrayList<>();// Initial IteratorIterator itr = list.iterator();list.add("GfG");System.out.println("List contains: ");while (itr.hasNext())System.out.println(itr.next());// iterator after adding an elementitr = list.iterator();System.out.println("List contains:");while (itr.hasNext())System.out.println(itr.next());}
}
输出
List contains:
List contains:
GfG
CopyOnWriteArrayList 的方法:
方法 | 说明 |
---|---|
add(E e) | 将指定元素添加到列表末尾 |
add(int index, E element) | 在列表的指定位置插入指定元素 |
addAll(Collection<? extends E> c) | 按照指定集合的迭代器返回的顺序,将指定集合中的所有元素追加到此列表的末尾 |
addAll(int index, Collection<? extends E> c) | 从指定位置开始,将指定集合中的所有元素插入此列表 |
addAllAbsent(Collection<? extends E> c) | 按照指定集合的迭代器返回的顺序,将指定集合中尚未包含在此列表中的所有元素追加到此列表的末尾 |
addIfAbsent(E e) | 如果元素不存在,则添加该元素 |
clear() | 删除列表中的所有元素 |
clone() | 返回该列表的浅层副本 |
contains(Object o) | 如果该列表包含指定元素,则返回 true |
containsAll(Collection<?> c) | 如果此列表包含指定集合的所有元素,则返回 true |
equals(Object o) | 将指定对象与此列表进行比较,以确定是否相等 |
forEach(Consumer<? super E> action) | 对 Iterable 的每个元素执行给定的操作,直到处理完所有元素或该操作抛出异常为止 |
get(int index) | 返回列表中指定位置的元素 |
hashCode() | 返回此列表的哈希代码值 |
indexOf(E e, int index) | 返回此列表中首次出现的指定元素的索引,从索引向前搜索,如果未找到该元素,则返回 -1 |
indexOf(Object o) | 返回此列表中首次出现的指定元素的索引,如果此列表不包含该元素,则返回 -1。 |
isEmpty() | 如果此列表不包含任何元素,则返回 true |
iterator() | 以正确的顺序返回此列表中元素的迭代器 |
lastIndexOf(E e, int index) | 返回此列表中指定元素最后一次出现的索引,从索引向后搜索,如果未找到该元素,则返回 -1 |
lastIndexOf(Object o) | 返回此列表中指定元素的最后出现的索引,如果此列表不包含该元素,则返回 -1 |
listIterator() | 返回此列表中元素的列表迭代器(按正确的顺序) |
listIterator(int index) | 返回此列表中元素的列表迭代器(按正确的顺序),从列表中的指定位置开始 |
remove(int index) | 删除此列表中指定位置的元素 |
remove(Object o) | 从此列表中删除指定元素的第一个匹配项(如果存在) |
removeAll(Collection<?> c) | 从此列表中删除指定集合中包含的所有元素 |
removeIf(Predicate<? super E> filter) | 删除此集合中满足给定谓词的所有元素 |
replaceAll(UnaryOperator< E > operator) | 将此列表的每个元素替换为将运算符应用于该元素的结果 |
retainAll(Collection<?> c) | 仅保留此列表中包含在指定集合中的元素 |
set(int index, E element) | 将此列表中指定位置的元素替换为指定的元素 |
size() | 返回此列表中的元素数 |
sort(Comparator<? super E> c) | 根据指定的 Comparator 引起的 Order 对这个列表进行排序 |
spliterator() | 返回此列表中元素的 Spliterator |
subList(int fromIndex, int toIndex) | 返回此列表中介于 fromIndex(含)和 toIndex(不含)之间的部分的视图 |
toArray() | 返回一个数组,其中包含此列表中的所有元素,并按正确的顺序(从第一个元素到最后一个元素) |
toArray(T[ ] a) | 返回一个数组,其中包含此列表中的所有元素,按正确的顺序(从第一个元素到最后一个元素);返回的数组的运行时类型是指定数组的运行时类型 |
toString() | 返回此列表的字符串表示形式 |
从接口 java.util.Collection 继承的方法:
方法 | 说明 |
---|---|
parallelStream() | 返回一个可能 parallelStream,并将此集合作为其源。 |
stream() | 返回以此集合作为其源的顺序 Stream。 |
注意: 当我们更喜欢在并发环境中使用类似于 ArrayList 的数据结构时,我们应该使用 CopyOnWriteArrayList。