Vector
- 线程安全的
使用synchronized
修饰方法。
add
/**
* Appends the specified element to the end of this Vector.
*
* @param e element to be appended to this Vector
* @return {@code true} (as specified by {@link Collection#add})
* @since 1.2
*/
public synchronized boolean add(E e) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
/**
* This implements the unsynchronized semantics of ensureCapacity.
* Synchronized methods in this class can internally call this
* method for ensuring capacity without incurring the cost of an
* extra synchronization.
*
* @see #ensureCapacity(int)
*/
private void ensureCapacityHelper(int minCapacity) {
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
说明:
这里主要注意ensureCapacityHelper
方法,当minCapacity - elementData.length > 0
时,将调用grow
方法扩容,要明确的是elementData.length
指的是数组的长度,minCapacity
是指当前的元素个数再加一。一开始的时候,我把elementData.length
也当做元素的个数,这样的话minCapacity - elementData.length > 0
就是必然成立的,那每一次add元素的时候,岂不都要进行扩容了。显然,这样理解是不对的。几番琢磨之后才醒悟过来,elementData.length
值的是内部分配的数组的长度,elementData.size()
才是元素的个数。这样的话,当添加元素前检测到数组已满时,就需要将数组扩容啦。数组扩容之后,再添加元素。
grow
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);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
参数minCapacity
实际上指的就是数组的最小容量,如果该值小于0的话,将会出现OutOfMemoryError
内存溢出的错误,具体见hugeCapacity
方法。
关于参数capacityIncrement
的定义如下:
/**
* The amount by which the capacity of the vector is automatically
* incremented when its size becomes greater than its capacity. If
* the capacity increment is less than or equal to zero, the capacity
* of the vector is doubled each time it needs to grow.
*
* @serial
*/
protected int capacityIncrement;
注释上说,这个变量就是数组每次扩容时需要增加的量,假设当前数组长度是10,capacityIncrement
等于5,那么,下次数组扩容后的大小就是15. 如果capacityIncrement
小于或等于0的话,下次扩容时,数组长度将增加一倍。同样假设当前数组长度是10,capacityIncrement
等于0,数组扩容后的大小是20,再扩容时,数组长度就是40了。
再回到grow
函数,实际分配的数组大小受数组最大长度限制的,数组的最大长度限制是Integer.MAX_VALUE - 8
。
小插曲:
看源码的时候,我注意到grow方法是没有使用synchronized
修饰的,在Vector
类中,有两个对外方法可以触发grow
,分别是
ensureCapacity(int minCapacity)
和 setSize(int newSize)
方法,然后我就想如果有多个线程分别执行这两个方法,触发grow
函数的执行,会不会像HashMap
一样在扩容的时候出现问题呢?不过后来仔细分析后发现,这里并不会有什么问题,因为HashMap
里面含有链表,而Vector
是纯数组操作,扩容的时候是根据索引将元素依次插入到扩容后的数组中,不依赖其他元素(链表依赖其前继节点)。