大致执行过程:首先获取当前数组存取元素,然后找我们要插入数据的下标值,找到了直接返回false,没找到的话,上锁,再次判断数组是否发生变化,这里多一次判断,我认为是为了防止这种可能性的出现:在判断完是否存在元素和加锁之间,另一个线程加入了我们要加的元素,不判断的话,那么同一个元素就有可能出现俩次,违背了addIfAbsent的意愿。加锁之后,如果数组并没有变的话,那么就执行CopyOnWriteArrayList的老套路,将原来的数据放到一个比原来长度长1的数组,最后一个空位放我们要放的数据。通过上述过程就实现了数据的唯一性,CopyOnWriteSet底层实现就是利用CopyOnWriteArrayList,唯一性就是利用addifabsent方法。
public boolean addIfAbsent(E e) {
// 获取元素数组, 取名为快照
Object[] snapshot = getArray();
// 检查如果元素存在,直接返回false
// 如果不存在再调用addIfAbsent()方法添加元素
return indexOf(e, snapshot, 0, ) >= 0 ? false :
addIfAbsent(e, snapshot);
}
private boolean addIfAbsent(E e, Object[] snapshot) {
final ReentrantLock lock = ;
// 加锁
();
try {
// 重新获取旧数组
Object[] current = getArray();
int len = ;
// 如果快照与刚获取的数组不一致
// 说明有修改
if (snapshot != current) {
// 重新检查元素是否在刚获取的数组里
int common = (, 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;
}
// 拷贝一份n+1的数组
Object[] newElements = (current, len + 1);
// 将元素放在最后一位
newElements[len] = e;
setArray(newElements);
return true;
} finally {
// 释放锁
();
}
}