Java CopyOnWriteArraySet
CopyOnWriteArraySet 是Java集合框架的一个成员。它是一个使用内部CopyOnWriteArrayList进行所有操作的Set。它是在JDK 1.5中引入的,我们可以说它是Set的线程安全版本。要使用这个类,我们需要从java.util.concurrent包中导入它。

它共享Set的一些属性,同时也有自己的属性,如图所示
- CopyOnWriteArraySet的内部实现只是CopyOnWriteArrayList。
- 多个线程能够同时执行更新操作,但对于每一次更新操作,都会创建一个单独的克隆副本。因为每次更新都会创建一个新的克隆副本,成本很高。因此,如果需要多个更新操作,不建议使用CopyOnWriteArraySet。
- 当一个线程在迭代Set的时候,其他线程可以进行更新,在这里我们不会得到任何运行时异常,比如ConcurrentModificationException 。
- CopyOnWriteArraySet类的迭代器只能进行只读操作,不应该进行删除操作,否则,我们会得到运行时异常UnsupportedOperationException 。
- 在以下应用中使用CopyOnWriteArraySet:集合的大小通常较小,只读操作的数量远远超过突变操作,并且你需要在遍历过程中防止线程之间的干扰。
- CopyOnWriteArraySet有助于最大限度地减少程序员控制的同步步骤,并将控制权转移到内置的、经过测试的API。
类的层次结构如下
java.lang.Object
↳ java.util.AbstractCollection<E>
↳ java.util.AbstractSet<E>
↳ java.util.concurrent.CopyOnWriteArraySet<E>
语法: 声明
public class CopyOnWriteArraySet<E> extends AbstractSet<E> implements Serializable
这里, E 是存储在这个集合中的元素的类型。它实现了 Serializable , **Iterable
CopyOnWriteArraySet的构造函数
1.CopyOnWriteArraySet() : 创建一个空集合。
CopyOnWriteArraySet<E> c = new CopyOnWriteArraySet<E>();
2.CopyOnWriteArraySet(Collection c ) : 创建一个包含指定集合中所有元素的集合。
CopyOnWriteArraySet<E> c = new CopyOnWriteArraySet<E>(Collection c);
例子
// Java Program to Illustrate CopyOnWriteArraySet Class
// Importing required classes
import java.util.*;
import java.util.concurrent.*;
// Main class
class ConcurrentDemo extends Thread {
static CopyOnWriteArraySet l
= new CopyOnWriteArraySet();
// Method
public void run()
{
// Child thread trying to add
// new element in the Set object
l.add("D");
}
// Method 2
// Main driver method
public static void main(String[] args)
{
// Adding elements
// using add() method
l.add("A");
l.add("B");
l.add("C");
// We create a child thread
// that is going to modify
// CopyOnWriteArraySet l.
ConcurrentDemo t = new ConcurrentDemo();
// Running the child thread
// using start() method
t.start();
// Waiting for the thread to
// add the element
// Try block to check for exceptions
try {
Thread.sleep(2000);
}
// Catch block to handle exceptions
catch (InterruptedException e) {
// Print statement
System.out.println(
"child going to add element");
}
System.out.println(l);
// Now we iterate through the
// CopyOnWriteArraySet and we
// wont get exception.
Iterator itr = l.iterator();
while (itr.hasNext()) {
String s = (String)itr.next();
System.out.println(s);
if (s.equals("C")) {
// Here we will get
// RuntimeException
itr.remove();
}
}
}
}
输出

迭代 CopyOnWriteArraySet
我们可以使用iterator()方法按照这些元素被添加的顺序遍历这个集合中的元素。返回的迭代器提供了一个不可改变的快照,即迭代器构建时的集合状态。因为这个属性, GeeksforGeeks 不会在第一次迭代时被打印出来。迭代时不需要同步。该迭代器不支持移除方法。
例子
// Java program to Illustrate Iterating Over
// CopyOnWriteArraySet class
// Importing required classes
import java.io.*;
import java.util.*;
import java.util.concurrent.*;
// Main class
// IteratingCopyOnWriteArraySet
class GFG {
// Main class
public static void main(String[] args)
{
// Creating an instance of CopyOnWriteArraySet
CopyOnWriteArraySet<String> set
= new CopyOnWriteArraySet<>();
// Initial an iterator
Iterator itr = set.iterator();
// Adding elements
// using add() method
set.add("GeeksforGeeks");
// Display message only
System.out.println("Set contains: ");
// Printing the contents
// of set to the console
while (itr.hasNext())
System.out.println(itr.next());
// Iterator after adding an element
itr = set.iterator();
// Display message only
System.out.println("Set contains:");
// Printing the elements to the console
while (itr.hasNext())
System.out.println(itr.next());
}
}
输出
Set contains:
Set contains:
GeeksforGeeks
CopyOnWriteArraySet中的方法
| 方法,包括 | 执行的动作 |
|---|---|
| add(E e) | 将指定的元素添加到这个集合中,如果它还没有存在的话。 |
| addAll(Collection extends E> c) | 如果指定的集合中的所有元素还没有出现,就把它们添加到这个集合中。 clear() | 移除这个集合中的所有元素。 contains(Object o) | 如果这个集合包含指定的元素,返回true。 containsAll(Collection> c) |
如果这个集合包含了指定集合的所有元素,则返回true。 |
| equals(Object o) | 将指定的对象与这个集合进行平等比较。 |
| forEach(Consumer super E> action) | 对Iterable的每个元素执行给定的动作,直到所有的元素都被处理完,或者该动作抛出一个异常。 isEmpty() | 如果这个集合不包含任何元素,返回true。 iterator() | 返回这个集合中包含的元素的迭代器,其顺序是这些元素被添加的顺序。 remove(Object o) | 如果指定的元素存在的话,从这个集合中移除它。 removeAll(Collection> c) |
从这个集合中移除包含在指定集合中的所有元素。 |
| removeIf(Predicate super E> filter) | 移除这个集合中满足给定谓词的所有元素。 retainAll(Collection> c) |
只保留这个集合中包含在指定集合中的元素。 |
| size() | 返回这个集合中元素的数量。 |
| spliterator() | 返回这个集合中的元素的Spliterator,按照这些元素被添加的顺序。 |
| toArray() | 返回一个包含这个集合中所有元素的数组。 |
| toArray(T[] a) | 返回一个包含这个集合中所有元素的数组;返回的数组的运行时类型是指定数组的类型。 |
从java.util.AbstractSet类继承的方法
| 方法 | 描述 |
|---|---|
| hashCode() | 返回此集合的哈希代码值。 |
继承自java.util.AbstractCollection类的方法
| 方法 | 描述 |
|---|---|
| toString() | 返回这个集合的字符串表示。 |
从接口java.util.Collection继承的方法
| 方法 | 描述 |
|---|---|
| parallelStream() | 返回一个以该集合为源的可能的并行流。 |
| stream() | 返回一个以这个集合为源的顺序流。 |
HashSet vs CopyOnWriteArraySet
| 属性 | 哈希集 | 写入数组上的复制(CopyOnWriteArraySet |
|---|---|---|
| 包 | 它属于java.util包 | 它属于java.util.concurrent包。 |
| 同步化 | 同步意味着只有一个线程可以访问或修改它。HashSet是不同步的。 | 它是同步的。 |
| 迭代器 | 我的方法iterator()和listiterator()返回的迭代器是故障快速的。 | 返回的迭代器是故障安全的。 |
| 添加在版本中 | 在JDK 1.2中添加 | 在JDK 1.5中添加 |
| 性能表现 | 因为它不是同步的,所以速度很快。 | 与HashSet相比,它要慢一些,因为它是同步的。 |
| 异常 | 它可能会抛出ConcurrentModificationException,因为许多线程可以同时访问它。 | 因为它是同步的,所以不会抛出ConcurrentModificationException。 |
极客教程