學習ArrayList的擴容機制


基於jdk8
1.首先我們看new ArrayList中
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
ArrayList底層就是一個Object數組;
這里DEFAULTCAPACITY_EMPTY_ELEMENTDATA是一個靜態的空的Object數組,所以ArrayList初始容量實際是0;
2.add方法
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}
private int size;
這里size默認值為0
private void ensureCapacityInternal(int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    ensureExplicitCapacity(minCapacity);
}
private static final int DEFAULT_CAPACITY = 10;
默認DEFAULT_CAPACITY容量為10,但是這是在使用add方法時,ArrayList才會進行初始化容量賦值。
首次加載時,elementData 對象肯定是一個空的Object數組,所以minCapacity = 10;
3.接下來我們再看看ensureExplicitCapacity這個方法;
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}
首次加載時minCapacity = 10,所以minCapacity - elementData.length肯定大於0,然后進行擴容判斷
還有就是當數組大小超過原有容量之后會進行擴容。擴容大小為 old +(old/2) -->1.5倍
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);
}
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
初次加載,oldCapacity = 0,所以newCapacity=0;newCapacity - minCapacity <0,所以最后初始化加載時newCapacity 為10了。
最后 newCapacity 會與MAX_ARRAY_SIZE進行比較,不能超過Integer的最大值減8
The maximum size of array to allocate.
Some VMs reserve some header words in an array.
Attempts to allocate larger arrays may result in
OutOfMemoryError: Requested array size exceeds VM limit
vm虛擬機會在數組中存放一些數據,所以不能等於Integer.MAX_VALUE(2147483647)
private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE)?
        Integer.MAX_VALUE :
        MAX_ARRAY_SIZE;
}

--拓展--

 因為ArrayList底層是一個Object數組,在多線程環境中可以會出現並發爭搶的問題,

java提供三種解決方案:

1.new Vector jdk1.0就出現的類

public void add(E e) {
            int i = cursor;
            synchronized (Vector.this) {
                checkForComodification();
                Vector.this.add(i, e);
                expectedModCount = modCount;
            }
            cursor = i + 1;
            lastRet = -1;
        }

加了synchronized保證add方法線程安全性,但是並發性急劇下降,所以在jdk1.2中才

會出現ArrayList這個類。

2.Collections.SynchronizedList(new ArrayList());

 public boolean add(E e) {
            synchronized (mutex) {return c.add(e);}
        }

3.new CopyOnWriteArrayList();

private transient volatile Object[] array;

使用volatile關鍵字,保證array數組可見性,禁止指令重排;

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();
        }
    }

add方法添加ReentrantLock 可重入鎖(遞歸鎖),保證add方法在多線程環境中程序執行

的安全性。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM