(二) 并发容器之 CopyOnWriteArraySet
程序员文章站
2024-01-07 21:45:34
同样, 用 List 的并发容器,当然也存在 Set 的并发容器,J.U.C 包下同样存在 CopyOnWriteArraySetCopyOnWriteArraySetpublic class CopyOnWriteArraySet extends AbstractSet implements java.io.Serializable { // 该类的所有操作由 CopyOnWriteArrayList 完成 private final C...
同样, 用 List 的并发容器,当然也存在 Set 的并发容器,J.U.C 包下同样存在 CopyOnWriteArraySet
CopyOnWriteArraySet
public class CopyOnWriteArraySet<E> extends AbstractSet<E>
implements java.io.Serializable {
// 该类的所有操作由 CopyOnWriteArrayList 完成
private final CopyOnWriteArrayList<E> al;
// 在实例化 CopyOnWriteArraySet 的时候,其实就是实例化了 CopyOnWriteArrayList
public CopyOnWriteArraySet() {
al = new CopyOnWriteArrayList<E>();
}
....
}
当然,这个是一个 Set ,在添加元素的时候需要多判断一下,直接查看他得 add(E) 方法
//发现它是调用了 CopyOnWriteArrayList 的 addIfAbsent(E) 方法
public boolean addIfAbsent(E e) {
Object[] snapshot = getArray();
return indexOf(e, snapshot, 0, snapshot.length) >= 0 ? false :
addIfAbsent(e, snapshot);
}
-----------------
// 查看 indexOf,从方法名就可以看出,这是一个得到元素下标的方法
// 至于是哪个元素的下标,根据 Set 的性质,你也猜的出来了
private static int indexOf(Object o, Object[] elements,
int index, int fence) {
if (o == null) {
for (int i = index; i < fence; i++)
if (elements[i] == null)
return i;
} else {
for (int i = index; i < fence; i++)
if (o.equals(elements[i]))
return i;
}
// 就是遍历数组,如果存在相同元素,返回它的下标,如果不存在,返回 -1
return -1;
}
-------------------------------
// 这里还需要注意,在高并发的情况下, 如果当前线程已经检查完数组,不存在相同元素
// 在返回 -1 后, 有可能另一个线程将数组的元素修改了,此时是否存在相同元素? 不得而知
// 所以在 addIfAbsent(E, Object[]) 方法需要判断一次
// 接着调用 addIfAbsent(E, Object[]) 方法
private boolean addIfAbsent(E e, Object[] snapshot) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
// 最新的数组,用于与快照比较
Object[] current = getArray();
int len = current.length;
// snapshot 相当于快照,为已经检查完毕的数组(不是最新的)
if (snapshot != current) {
// 如果快照与最新的数组不匹配
int common = Math.min(snapshot.length, len);// 取最小值
for (int i = 0; i < common; i++)
// 两个数组元素比较
if (current[i] != snapshot[i] && eq(e, current[i]))
return false;
// 再次检查, 需要添加的元素与最新的数组是否存在相同元素
if (indexOf(e, current, common, len) >= 0)
return false;
}
// 如果不存在相同元素, 复制一份数组,追加元素
Object[] newElements = Arrays.copyOf(current, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
说到 Set, 再来看看 HashSet
HashSet
public class HashSet<E> extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable {
// HashSet 的所有操作都是交给 HashMap 完成
private transient HashMap<E,Object> map;
// 由于 HashMap 需要 K-V 两个参数,该常量作为 value 放入 HashMap
private static final Object PRESENT = new Object();
// 同 CopyOnWriteArraySet, 在实例化 HashSet 的时候其实就是实例化了 HashMap
public HashSet() {
map = new HashMap<>();
}
....
}
由于 HashMap 的特性 : Key 不唯一,JDK 直接使用 HashMap 来操作 HashSet, 查看 HashSet 的 add 方法
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
就是调用了 HashMap 的 put 方法, 使用一个常量作为 value 放入 HashMap 中
本文地址:https://blog.csdn.net/Gp_2512212842/article/details/107691003