前言
CopyOnWriteArraySet也是JUC下常用容器,其底層實作是基于CopyOnWriteArrayList的,關于CopyOnWriteArrayList的詳情可以檢視
【從入門到放棄-Java】并發程式設計-JUC-CopyOnWriteArrayList,接下來我們看下源碼。
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一樣,更适用于讀多寫少的并發操作中。
詳細原因在
中以及解釋過了,這裡不再贅述。
值得一提的是,常用的非并發容器HashSet,是基于HashMap實作的,利用HashMap中Entry的key做到唯一值,Entry的value是一個不可變靜态對象Object。但是JUC中并發Set是卻不是基于Map的,學習完這三章并發容器,你能回答這是為什麼嗎?可以在評論中留言,我們一起探讨下哦~
更多文章
見我的部落格:
https://nc2era.comwritten by
AloofJr,轉載請注明出處