List
ArrayList
List就是一個動態的數組 如何動態的擴容當容量達到一定閾值的時候會新建一個大容量的數組然後把舊的數組的數據copy到新的數組哪裏去。需要注意的new ArrayList如果不帶初始化容量的情況 new ArrayList()的時候默認是空的一個數組。只有在操作add的時候纔會去初始化一個容量默認爲10的數組。
modCount 這個需要注意下 我們知道 java.util.HashMap 不是線程安全的,因此如果在使用迭代器的過程中有其他線程修改了map,那麼將拋出ConcurrentModificationException,這就是所謂fail-fast策略。這一策略在源碼中的實現是通過modCount域,modCount 顧名思義就是修改次數,對HashMap內容的修改都將增加這個值,那麼在迭代器初始化過程中會將這個值賦給迭代器的expectedModCount。在迭代過程中,判斷modCount 跟 expectedModCount是否相等,如果不相等就表示已經有其他線程修改了 Map:注意到 modCount聲明爲 volatile,保證線程之間修改的可見性。 modCount到底是幹什麼的呢 所以使用在循環中刪除同一個list的元素的時候需要好好對待,分分給你拋異常,儘量使用迭代器吧。
// ArrayList擴容的代碼
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
foreach中刪除異常出現錯誤的原因(modCount的原因)
foreach只是java語言的語法糖,本質上還是由Iterator來迭代的,但在刪除時,調用的是list的remove方法,正是這裏引發了修改異常。
ArrayList小結:在使用arrayList的時候如果可以大概知道數組的長度返回建議指定大小,避免數組copy的消耗。
CopyOnWriteArrayList
CopyOnWriteArrayList出來的原因就是一個線程安全的一個ArrayList,
只有作爲共享list的時候才考慮使用,所有安全的東西是比較慢的。
線程安全的原理直接貼代碼其實根據它的名字大概也可以猜測出多少東西複製然後再寫入的一個ArrayList(取名很優秀)add的方法都要上一把鎖ReentrantLock鎖整個過程了,這個代碼很簡單易懂,優秀。
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();
}
}
CopyOnWriteArrayList小結:就是寫入操作的時候加鎖具體看代碼。
Vector
這個玩意跟ArrayList就是一個東西來的只是加了synchronized 全部都加了 get add 都加了 重的很一般不用這個玩意。
附錄
接口名稱 | 作用 |
---|---|
List | list容器接口 |
RandomAccess | 支持隨機訪問 |
Cloneable | 支持克隆 |
java.io.Serializable | 支持序列化 |