なぜ我々は、取得する必要がないReentrant
のコード下記のとおりロックをCopyOnWriteArrayList
我々は内の要素を追加したときList
。私たちは、元の配列のコピーを作成し、それを変更しています。我々は取得していない場合、私たちはどのような副作用を持つことができるlock
最初の場所で?
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();
}
}
あなたは、マルチスレッドコンテキストでグローバル変数に任意の操作をしようと、それは両方になりたいされている場合、原子と確保メモリの可視性を使用すると、その操作の周りにロックを持っている必要があり、他のスレッドに。
ここでgetArray()
グローバルインスタンスフィールドを返していますObject[] array
。
この例ではそう:
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
そこにこのコードブロックの周りに何もロックがなく、2つのスレッドが、それはそのスレッド1とスレッド2が起こる両方読んでも、その場合には、要素を追加しようとしていると仮定した場合と同じ値をlen
と同じインデックスに新しい要素を割り当てます。
どのよう、これまで他のスレッドによって以前の値セットを上書きします最後に新しい値を代入を通します。
さらに説明するために、両方のスレッド1とスレッド2が同じ値の読みと言うlen
今は1スレッドすることから、新しい配列を作成するために行くArrays.copyOf(elements, len + 1)
と、変数の値を代入するe
中len
、新しい配列の位置を。
スレッド1が使用して新しいアレイを設定することができます前にsetArray(newElements)
スレッド2を一方の同じ値でこの処理を続行しますlen
。それは新しい配列インスタンスを作成しますが、新しい要素が設定されたインデックスが同じであろうがlen
、スレッド1によって使用されます。
スレッド2つの用途は、ときにsetArray(newElements)
、スレッド1の後に新しい値を持つ新しい配列を設定するには、以前の配列値len
番目のインデックスは、スレッド2による新たな要素セットで上書きされます。