CopyOnWriteArraySet、HashSet 都是不允许重复元素的集合,CopyOnWriteArraySet 线程安全,HashSet 线程不安全,CopyOnWriteArraySet 底层是基于动态数组实现,并通过CopyOnWriteArrayList 相关方法操作,HashSet 是基于散列表实现。 CopyOnWriteArraySet 是无序的,而CopyOnWriteArrayList 是有序的,当多个线程对CopyOnWriteArraySet 进行写操作时,首先也是获取相关的锁资源权限才能进行写操作,也是复制一份样本进行,写完成通过地址引用重新赋值给原始变量。同时释放锁资源,当然在写操作时可以进行读并发不阻塞,但是不能保证数据的实时性,由于写操作会进行复制,所以会造成空间的一定浪费,故也是使用在写少读多的并发场景。
继承关系
Iterable 说明具有迭代器的功能
Collection 说明含有集合基本的方法
Set 拥有Set集合的所有方法
AbstractSet 重写removeAll方法
初始化方式
//有参
public CopyOnWriteArraySet(Collection<? extends E> c)
//无参
public CopyOnWriteArraySet()
方式一/无参
CopyOnWriteArraySet 内部维护了一个CopyOnWriteArrayList的al变量,调用无参构造进行实例化CopyOnWriteArraySet 时,直接创建一个CopyOnWriteArrayList 并赋值给 al 变量
public CopyOnWriteArraySet() {
al = new CopyOnWriteArrayList<E>();
}
方式二/有参
public CopyOnWriteArraySet(Collection<? extends E> c) {
if (c.getClass() == CopyOnWriteArraySet.class) {
@SuppressWarnings("unchecked")
CopyOnWriteArraySet<E> cc = (CopyOnWriteArraySet<E>)c;
al = new CopyOnWriteArrayList<E>(cc.al);
}else {
al = new CopyOnWriteArrayList<E>();
al.addAllAbsent(c);
}
}
首先传入集合类型的 c 变量判断是不是CopyOnWriteArraySet 类型,如果是则直接强制性转换成CopyOnWriteArraySet 并调用CopyOnWriteArrayList 有参构造创建集合并 将 c 添加进去。如果不是CopyOnWriteArraySet 类型,初始化CopyOnWriteArrayList 通过方法addAllAbsent 将c集合中的数据进行去重并添加。
CopyOnWriteArrayList.addAllAbsent()方法
public int addAllAbsent(Collection<? extends E> c) {
//将集合c转换成数组
Object[] cs = c.toArray();
//如果 c 不是 ArrayList 类型 进行拷贝
if (c.getClass() != ArrayList.class) {
cs = cs.clone();
}
//如果 cs 为空 结束方法
if (cs.length == 0)
return 0;
//获取锁资源权限
synchronized (lock) {
//获取CopyOnWriteArrayList原始集合数组
Object[] es = getArray();
int len = es.length;
int added = 0;
// uniquify and compact elements in cs
for (int i = 0; i < cs.length; ++i) {
Object e = cs[i];
//说明元素在 es 集合中不存在
if (indexOfRange(e, es, 0, len) < 0 && indexOfRange(e, cs, 0, added) < 0)
//赋值给 added 索引 added 进行+1
cs[added++] = e;
}
//说明已经去重了
if (added > 0) {
//创建新数组(长度为len + added)并拷贝 es
Object[] newElements = Arrays.copyOf(es, len + added);
//将 cs 数据拷贝到 newElements 中
System.arraycopy(cs, 0, newElements, len, added);
//重新设置array引用为 newElements 地址
setArray(newElements);
}
//返回添加的数据个数
rturn added;
}
//释放锁资源
}
添加数据
CopyOnWriteArraySet.add(E e) -> CopyOnWriteArrayList.addIfAbsent(e) ->
CopyOnWriteArrayList.addIfAbsent(E e, Object[] snapshot)
//简单方法
public boolean add(E e) {
return al.addIfAbsent(e);
}
public boolean addIfAbsent(E e) {
//获取当前的数组对象快照
Object[] snapshot = getArray();
//如果元素e在snapshot中的不存在并且 添加成功返回成功标记
return indexOfRange(e, snapshot, 0, snapshot.length) < 0 && addIfAbsent(e, snapshot);
}
private boolean addIfAbsent(E e, Object[] snapshot) {
//获取锁资源权限
synchronized (lock) {
//获取当前数组
Object[] current = getArray();
int len = current.length;
//如果当前快照不是 当前数组
if (snapshot != current) {
// 取最小值
int common = Math.min(snapshot.length, len);
//判断元素e在current数组中是否存在 如果存在 直接返回不添加
for (int i = 0; i < common; i++)
if (current[i] != snapshot[i] && Objects.equals(e, current[i]))
return false;
if (indexOfRange(e, current, common, len) >= 0)
return false;
}
//进行数据拷贝
Object[] newElements = Arrays.copyOf(current, len + 1);
//将新值放到len的位置
newElements[len] = e;
//将心的引用复制给array
setArray(newElements);
//返回成功标记
return true;
}
//释放锁资源
}
删除数据
remove(Object o) -> CopyOnWriteArrayList.remove(Object o)
public boolean remove(Object o) {
//获取原始数组的快照
Object[] snapshot = getArray();
//获取元素O在原始快照中的索引
int index = indexOf(o, snapshot, 0, snapshot.length);
//移除元素
return (index < 0) ? false : remove(o, snapshot, index);
}
private boolean remove(Object o, Object[] snapshot, int index) {
//获取资源锁
final ReentrantLock lock = this.lock;
lock.lock();
try {
//获取当前数组
Object[] current = getArray();
//当前数组的长度
int len = current.length;
//如果当前数组不是快照 查找O元素在新数组中的索引
if (snapshot != current) findIndex: {
int prefix = Math.min(index, len);
for (int i = 0; i < prefix; i++) {
if (current[i] != snapshot[i] && eq(o, current[i])) {
index = i;
break findIndex;
}
}
if (index >= len)
return false;
if (current[index] == o)
break findIndex;
index = indexOf(o, current, index, len);
if (index < 0)
return false;
}
//重新创建数组
Object[] newElements = new Object[len - 1];
//赋值数组
System.arraycopy(current, 0, newElements, 0, index);
System.arraycopy(current, index + 1, newElements, index, len - index - 1);
//数组索引从新指向
setArray(newElements);
return true;
} finally {
//释放锁资源
lock.unlock();
}
}
遍历数据
public Iterator<E> iterator()
public void forEach(Consumer<? super E> action)
forEach(Consumer<? super E> action) -> CopyOnWriteArrayLis.forEach(Consumer<? super E> action)
public void forEach(Consumer<? super E> action) {
//如果集合是空则抛出异常
if (action == null) throw new NullPointerException();
//获取袁术数组
Object[] elements = getArray();
int len = elements.length;
//进行迭代
for (int i = 0; i < len; ++i) {
@SuppressWarnings("unchecked") E e = (E) elements[i];
//消费型接口
action.accept(e);
}
}