# Java `CopyOnWriteArraySet`类

> 原文： [https://howtodoinjava.com/java/collections/java-copyonwritearrayset/](https://howtodoinjava.com/java/collections/java-copyonwritearrayset/)

Java `CopyOnWriteArraySet`是[**`HashSet`**](https://howtodoinjava.com/java/collections/java-hashset/)的[线程安全](https://howtodoinjava.com/java/multi-threading/what-is-thread-safety/)变体，其所有操作均使用基础`CopyOnWriteArrayList`。

与`CopyOnWriteArrayList`类似，它的**不可变快照式**[迭代器](https://howtodoinjava.com/java/collections/java-iterator/)方法在创建迭代器时使用对数组状态（在后备列表内）的引用。 这在遍历操作远远超过集合更新操作且我们不想同步遍历并且在更新集合时仍希望线程安全的用例中很有用。

```java
Table of Contents

1\. CopyOnWriteArraySet Hierarchy
2\. CopyOnWriteArraySet Features
3\. CopyOnWriteArraySet Example
4\. CopyOnWriteArraySet Constructors
5\. CopyOnWriteArraySet Methods
6\. CopyOnWriteArraySet Usecases
7\. CopyOnWriteArraySet Performance
8\. Conclusion
```

## 1\. `CopyOnWriteArraySet`层次结构

`CopyOnWriteArraySet`类扩展了`AbstractSet`类并实现了`Serializable`接口。

```java
public class CopyOnWriteArraySet<E>
		extends AbstractSet<E>
		implements Serializable

{
	private final CopyOnWriteArrayList<E> al;

	//implementation
}

```

## 2\. `CopyOnWriteArraySet`特性

有关 Java `CopyOnWriteArraySet`类的重要知识是：

*   作为正常设置的数据结构，它不允许重复。
*   `CopyOnWriteArraySet`类实现`Serializable`接口并扩展`AbstractSet`类。
*   使用`CopyOnWriteArraySet`进行更新操作成本很高，因为每个突变都会创建基础数组的克隆副本并向其添加/更新元素。
*   它是`HashSet`的线程安全版本。 每个访问该集合的线程在初始化此集合的迭代器时都会看到自己创建的后备数组快照版本。
*   因为它在创建迭代器时获取基础数组的快照，所以它不会抛出`ConcurrentModificationException`。
*   不支持迭代器上的变异操作。 这些方法抛出`UnsupportedOperationException`。
*   `CopyOnWriteArraySet`是**同步集**的并发替代，并且在迭代次数超过突变次数时提供了更好的并发性。
*   它允许重复的元素和异构对象（使用泛型来获取编译时错误）。
*   因为它每次创建迭代器时都会创建基础数组的新副本，所以**性能比`HashSet`慢**。

## 3\. Java `CopyOnWriteArraySet`示例

Java 程序，用于显示在不同时间创建的迭代器如何查看`CopyOnWriteArraySet`中集合的快照版本。 在给定的示例中，当列表具有元素（`1,2,3`）时，我们首先创建了`list`和`itr1`。

然后，我们在列表中添加了另一个元素，并再次创建了一个迭代器`itr2`。

最后，我们验证了两个迭代器中的元素。

```java
CopyOnWriteArraySet<Integer> set = new CopyOnWriteArraySet<>(Arrays.asList(1,2,3));

System.out.println(set);	//[1, 2, 3]

//Get iterator 1
Iterator<Integer> itr1 = set.iterator();

//Add one element and verify set is updated
set.add(4);
System.out.println(set);	//[1, 2, 3, 4]

//Get iterator 2
Iterator<Integer> itr2 = set.iterator();

System.out.println("====Verify Iterator 1 content====");

itr1.forEachRemaining(System.out :: println);	//1,2,3

System.out.println("====Verify Iterator 2 content====");

itr2.forEachRemaining(System.out :: println);	//1,2,3,4

```

程序输出。

```java
[1, 2, 3]
[1, 2, 3, 4]
====Verify Iterator 1 content====
1
2
3
====Verify Iterator 2 content====
1
2
3
4

```

## 4\. `CopyOnWriteArraySet`构造器

*   **`CopyOnWriteArraySet()`**：创建一个空集。
*   **`CopyOnWriteArraySet(Collection c)`**：创建一个包含指定集合元素的集合，其顺序由集合的迭代器返回。

## 5\. `CopyOnWriteArraySet`方法

*   **`boolean add(object o)`**：如果指定的元素尚不存在，则将其添加到此集合中。
*   **`boolean addAll(collection c)`**：将指定集合中的所有元素（如果尚不存在）添加到此集合中。
*   **`void clear()`**：从该集合中删除所有元素。
*   **`boolean contains(Object o)`**：如果此集合包含指定的元素，则返回 true。
*   **`boolean isEmpty()`**：如果此集合不包含任何元素，则返回 true。
*   **`Iterator iterator()`**：以添加这些元素的顺序在此集合中包含的元素上返回一个迭代器。
*   **`boolean remove(Object o)`**：如果存在指定元素，则从此集合中删除该元素。
*   **`int size()`**：返回此集合中的元素数。

## 6\. Java `CopyOnWriteArraySet`用例

在集大小通常保持较小的应用程序中使用`CopyOnWriteArraySet`，只读操作大大超过了可变操作，并且您需要防止遍历期间线程之间的干扰。

`CopyOnWriteArraySet`有助于最小化程序员控制的同步步骤，并将控制权移交给经过良好测试的内置 API。

## 7\. Java `CopyOnWriteArraySet`性能

由于每次更新集时都会增加创建新支持数组的步骤，因此其性能比`HashSet`差。
读取操作没有性能开销，并且两个类执行相同的操作。

## 8\. 总结

在本 Java 集合教程中，我们学习了使用`CopyOnWriteArraySet`类，其构造器，方法和用例。

我们了解了在 Java 中`CopyOnWriteArraySet`的内部工作原理，以及`CopyOnWriteArraySet`与`CopyOnWriteArrayList`的工作原理。

我们通过 **Java `CopyOnWriteArraySet`示例程序**演示了快照迭代器的工作方式。

在评论中把您的问题交给我。

学习愉快！

参考：

[`CopyOnWriteArraySet` Java 文档](https://docs.oracle.com/javase/10/docs/api/java/util/concurrent/CopyOnWriteArraySet.html)