[ArrayListの実装]
ArrayListの実装には、主に次のものが含まれます。ObjectelementDataの配列はすべての要素を保持し、size変数は現在の配列に追加された要素の数を保持します。
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* will be expanded to DEFAULT_CAPACITY when the first element is added.
*/
transient Object[] elementData; // non-private to simplify nested class access
/**
* The size of the ArrayList (the number of elements it contains).
*
* @serial
*/
private int size;
【追加操作のソースコード】
追加操作は、大きく2つのステップに分けられます。1。リストの容量が十分であるかどうか、および拡張が必要かどうかを判断します。2。リストの要素配列に要素を配置します。
スレッドの不安定さの隠れた危険性(1):
リストの現在のサイズが8、つまりsize = 8であるとします。
スレッドAはaddメソッドの入力を開始します。つまり、サイズ8の値を取得し、ensureCapacityInternalメソッドを呼び出して容量を決定します。
スレッドBもこの時点でaddメソッドに入り、取得するサイズ値も8であり、ensureCapacityInternalメソッドの呼び出しも開始します。
スレッドAは、必要なサイズが8 + 1 = 9であり、elementDataのサイズがわずか9であることを検出しました。これは、対応できます。そのため、拡張して戻ることはありません。
スレッドBは、デマンドサイズが9であることも検出します。これは、対応して返すこともできます。
スレッドAは値の設定操作を開始し、elementData [size ++] = eを実行した後、サイズは9になります。
スレッドBも値操作の設定を開始し、elementData [size ++]、つまりelementData [ 9 ] = eを実行します。このとき、範囲外の配列例外ArrayIndexOutOfBoundsExceptionが報告されます。
スレッドの不安定さの隠れた危険性(2):
さらに、elementData [size ++] = e設定値の操作も、スレッドのセキュリティを低下させます。この操作はアトミック操作ではないため、次の2つのステップで構成されます。
1、elementData [size] = e;
2、サイズ=サイズ+1;
elementDataの現在のサイズが0であるとします。
スレッドAは、要素「A」を追加し、elementData添え字が0の位置に「A」を配置します。
次に、スレッドBも要素「B」を追加し、最初の操作に進みました。このとき、スレッドBで取得したサイズ値は0のままなので、スレッドBもelementData添え字が0の位置に「B」を配置します。
次に、スレッドAはサイズの値を1に増やし、スレッドBはサイズの値を2に増やします。
スレッドAとBの実行が完了した後、elementDataの期待される結果は次のとおりです。サイズは2、elementData [0] = "A"、elementData [1] = "B"。
実際の状況は次のとおりです。サイズは2、elementData [0] = "B"、elementData [1] = nullです。
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return <tt>true</tt> (as specified by {@link Collection#add})
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}