copyOnWriteArrayList与Vector都是用来替换多线程下List的使用的
这里通过源码分析一下他们的实现
Vector
底层为数组实现 初始容量为10
//第一个参数为数组初始大小,第二个参数为扩容时需要增加的大小
public Vector(int initialCapacity, int capacityIncrement) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
this.capacityIncrement = capacityIncrement;
}
而它对于增加和删除元素,是通过加锁来保证多线程下的安全性的,如超过默认大小 则进行扩容
public synchronized boolean add(E e) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
扩容时 如果构造时未指定每次扩容的大小,则扩为原来二倍
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
由于加锁的缘故,大多情况下时能保证线程安全的,但是,在这种情况下不行,如下:
// 之所以不行的原因是当某个线程获取到这个锁,
//判断完之后释放了,但是到执行add还是有间隔,
//所以有可能会被另一个线程获取,然后时间片段结束后释放
if(Vector.contains(1)){
Vector.add(2)
}
所以,对于Vector的线程安全性,还需要自己代码加锁来保证,这样的话,首先是加锁会大大降低效率,其次也并没有完全保证线程安全,所以推荐使用下面的copyOnWriteArrayList
CopyOnWriteArrayList
它底层也是用数组实现,但是它和Vector最大的不同以及优于它的一点就在于它对于add/remove元素,并不在方法上面加锁,它采用的是方法内用重入锁,创建新数组并将原数组复制到新数组,将元素添加到新数组,将引用指向新数组,解锁。具体源码如下:
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
//拿到原数组
Object[] elements = getArray();
//拿到原数组长度
int len = elements.length;
//复制原数组到新数组
Object[] newElements = Arrays.copyOf(elements, len + 1);
//插入新元素
newElements[len] = e;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
它比Vector的安全性和效率都会高一点