前言
CopyOnWriteArraySet也是JUC下常用容器,其底层实现是基于CopyOnWriteArrayList的,关于CopyOnWriteArrayList的详情可以查看【从入门到放弃-Java】并发编程-JUC-CopyOnWriteArrayList,接下来我们看下源码。
CopyOnWriteArraySet
CopyOnWriteArraySet
/**
* Creates an empty set.
*/
//简单粗暴,只有一个成员变量al,是CopyOnWriteArrayList类型的,初始化时,new一个CopyOnWriteArrayList赋值给al。
public CopyOnWriteArraySet() {
al = new CopyOnWriteArrayList<E>();
}
/**
* Creates a set containing all of the elements of the specified
* collection.
*
* @param c the collection of elements to initially contain
* @throws NullPointerException if the specified collection is null
*/
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);
}
}
add
/**
* Adds the specified element to this set if it is not already present.
* More formally, adds the specified element {@code e} to this set if
* the set contains no element {@code e2} such that
* {@code Objects.equals(e, e2)}.
* If this set already contains the element, the call leaves the set
* unchanged and returns {@code false}.
*
* @param e element to be added to this set
* @return {@code true} if this set did not already contain the specified
* element
*/
public boolean add(E e) {
//调用CopyOnWriteArrayList的addIfAbsent方法。
return al.addIfAbsent(e);
}
//看下CopyOnWriteArrayList的addIfAbsent方法如何实现。
/**
* Appends the element, if not present.
*
* @param e element to be added to this list, if absent
* @return {@code true} if the element was added
*/
public boolean addIfAbsent(E e) {
Object[] snapshot = getArray();
//先查找e是否在存在,不存在的话 调用addIfAbsent(E e, Object[] snapshot)方法
return indexOfRange(e, snapshot, 0, snapshot.length) < 0
&& addIfAbsent(e, snapshot);
}
/**
* A version of addIfAbsent using the strong hint that given
* recent snapshot does not contain e.
*/
private boolean addIfAbsent(E e, Object[] snapshot) {
//加锁
synchronized (lock) {
Object[] current = getArray();
int len = current.length;
//加锁后check下快照是否被改动
if (snapshot != current) {
//如果改动过,则判断改动后的数组是否包含要添加的元素,如果有的话,则返回失败
// Optimize for lost race to another addXXX operation
int common = Math.min(snapshot.length, len);
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);
newElements[len] = e;
//替换原数组。
setArray(newElements);
return true;
}
}
addAll
/**
* Adds all of the elements in the specified collection to this set if
* they're not already present. If the specified collection is also a
* set, the {@code addAll} operation effectively modifies this set so
* that its value is the <i>union</i> of the two sets. The behavior of
* this operation is undefined if the specified collection is modified
* while the operation is in progress.
*
* @param c collection containing elements to be added to this set
* @return {@code true} if this set changed as a result of the call
* @throws NullPointerException if the specified collection is null
* @see #add(Object)
*/
public boolean addAll(Collection<? extends E> c) {
//直接调用CopyOnWriteArrayList的addAllAbsent方法。
return al.addAllAbsent(c) > 0;
}
/**
* Appends all of the elements in the specified collection that
* are not already contained in this list, to the end of
* this list, in the order that they are returned by the
* specified collection's iterator.
*
* @param c collection containing elements to be added to this list
* @return the number of elements added
* @throws NullPointerException if the specified collection is null
* @see #addIfAbsent(Object)
*/
public int addAllAbsent(Collection<? extends E> c) {
//将要添加的元素变为数组
Object[] cs = c.toArray();
if (cs.length == 0)
return 0;
//加锁
synchronized (lock) {
Object[] es = getArray();
int len = es.length;
int added = 0;
// uniquify and compact elements in cs
//遍历要添加的数组,如果在List的数组中不存在此元素,则添加到cs数组中
for (int i = 0; i < cs.length; ++i) {
Object e = cs[i];
if (indexOfRange(e, es, 0, len) < 0 &&
indexOfRange(e, cs, 0, added) < 0)
cs[added++] = e;
}
if (added > 0) {
Object[] newElements = Arrays.copyOf(es, len + added);
//将cs数组的前added个元素添加在List数组后面
System.arraycopy(cs, 0, newElements, len, added);
//替换原数组
setArray(newElements);
}
return added;
}
}
remove
/**
* Removes the specified element from this set if it is present.
* More formally, removes an element {@code e} such that
* {@code Objects.equals(o, e)}, if this set contains such an element.
* Returns {@code true} if this set contained the element (or
* equivalently, if this set changed as a result of the call).
* (This set will not contain the element once the call returns.)
*
* @param o object to be removed from this set, if present
* @return {@code true} if this set contained the specified element
*/
public boolean remove(Object o) {
//直接调用CopyOnWriteArrayList的remove
return al.remove(o);
}
总结
通过源码分析,我们了解到,CopyOnWriteArraySet主要是依赖CopyOnWriteArrayList来实现各方法的。
因此与CopyOnWriteArrayList一样,更适用于读多写少的并发操作中。
详细原因在【从入门到放弃-Java】并发编程-JUC-CopyOnWriteArrayList中以及解释过了,这里不再赘述。
值得一提的是,常用的非并发容器HashSet,是基于HashMap实现的,利用HashMap中Entry的key做到唯一值,Entry的value是一个不可变静态对象Object。但是JUC中并发Set是却不是基于Map的,学习完这三章并发容器,你能回答这是为什么吗?可以在评论中留言,我们一起探讨下哦~
更多文章
见我的博客:https://nc2era.com
written by AloofJr,转载请注明出处