CopyOnWriteArrayList源码阅读(二)

2015-01-27 10:15:35 · 作者: · 浏览: 47
lements, index, numMoved); setArray(newElements); } return (E)oldValue; } finally { lock.unlock(); } }remove(Object)方法,分配一个len-1大小的新数组,遍历原来数组,如果找到则将原来数组以后的元素拷贝到新数组中并将list设置为新数组,否则直接给新数组赋值上原来数组。

public boolean remove(Object o) {
	final ReentrantLock lock = this.lock;
	lock.lock();
	try {
	    Object[] elements = getArray();
	    int len = elements.length;
	    if (len != 0) {
		// Copy while searching for element to remove
		// This wins in the normal case of element being present
		int newlen = len - 1;
		Object[] newElements = new Object[newlen];

		for (int i = 0; i < newlen; ++i) {
		    if (eq(o, elements[i])) {
			// found one;  copy remaining and exit
			for (int k = i + 1; k < len; ++k)
			    newElements[k-1] = elements[k];
			setArray(newElements);
			return true;
		    } else
			newElements[i] = elements[i];
		}

		// special handling for last cell
		if (eq(o, elements[newlen])) {
		    setArray(newElements);
		    return true;
		}
	    }
	    return false;
	} finally {
	    lock.unlock();
	}
 }

迭代器的实现

ArrayList中迭代器支持fast fail,一旦检测到遍历过程中发送了修改则会抛出ConcurrentModificationException;CopyOnWriteArrayList的迭代器由于修改的时候都会重新copy一份数组,因此不存在并发修改问题,也不会抛出ConcurrentModificationException。同样支持单向和双向迭代器,其iterator和listIterator方法都是通过内部类COWIterator创建,只是前者返回接口限定为单向迭代Iterator

COWIterator定义

/** Snapshot of the array **/
private final Object[] snapshot;
/** Index of element to be returned by subsequent call to next.  */
private int cursor;

构造器

private COWIterator(Object[] elements, int initialCursor) {
            cursor = initialCursor;
            snapshot = elements;
}
iterator和listIterator中会传递当前数组的引用和cursor(无参方法为0,有参数方法为对应值)

常见方法

public boolean hasNext() {
    return cursor < snapshot.length;
}
public boolean hasPrevious() {
    return cursor > 0;
}
public E next() {
	if (! hasNext())
        throw new NoSuchElementException();
	return (E) snapshot[cursor++];
}
public E previous() {
	if (! hasPrevious())
        throw new NoSuchElementException();
	return (E) snapshot[--cursor];
}
另外其他add、remove和set修改容器的方法都没有实现,直接throw new UnsupportedOperationException();

总结

1. CopyOnWriteArrayList的迭代器保留一个执行底层基础数组的引用,这个数组当前位于迭代器的起始位置,由于基础数组不会被修改(修改都是复制一个新的数组),因此对其同步只需要保证数组内容的可见性。多个线程可以同时对这个容器进行迭代,而不会彼此干扰或者与修改容器的线程互相干扰。不会抛出CocurrentModificationException,并且返回元素与创建迭代器创建时的元素完全一致,不必考虑之后修改操作带来影响。

2. 每次修改容器都会复制底层数组,这需要一定开销,特别是容器规模较大。仅当迭代操作远远多于修改操作时,才应该使用CopyOnWriteArrayList。