CopyOnWriteArrayListとが提供同時Javaコンテナとの契約で、それはスレッドセーフArrayListに、書き込み動作は、基になる配列の新しいコピーを作成することによって実現されている別の読み取りおよび書き込み同時方式を、私たちは、「このコンテナを呼び出すことができます「レプリケータを書くときに、Javaと似たコンテナ内の契約もCopyOnWriteSetが、CopyOnWriteSetに任意の自然の呼び出しはCopyOnWriteArrayListとあります。
原則
コレクションフレームワークのArrayListは、非スレッドセーフであるベクトル、それはスレッドセーフですが、それは非常にシンプルなロック同期メカニズムので、パフォーマンスの低下です。そしてCopyOnWriteArrayListとは、同時治療戦略の異なる種類(提供別々の読み取りと書き込みを)。
CopyOnWriteArrayListとコンテナが同時読み取りを許可し、読み出し動作にはロック、より高いパフォーマンスではありません。例えば、容器に要素を追加するなどの書き込み操作のための新たな容器への参照点の終了後に元の容器は、次に、現在のコンテナの最初のコピーを作成し、新しいコピーに書き込み動作を行います。
/** The lock protecting all mutators */
final transient ReentrantLock lock = new ReentrantLock();
/** The array, accessed only via getArray/setArray. */
private transient volatile Object[] array;
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return {@code true} (as specified by {@link Collection#add})
*/
public boolean add(E e) {
//获取锁
final ReentrantLock lock = this.lock;
lock.lock();
try {
//获取原数组
Object[] elements = getArray();
//获取原数组个数
int len = elements.length;
//拷贝一份原数组并+1,生成的新数组的len位置上增加元素
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
//替换原数组
setArray(newElements);
return true;
} finally {
//释放锁
lock.unlock();
}
}
私たちは、ロックを取得し、時間の新しい要素でそれを見ると、新しい要素を追加する新しい配列+1、この時間を生成して、新しい配列の場所を追加し、最終的にライン上の元の配列を置き換えることができます。
public E remove(int index) {
//获取锁
final ReentrantLock lock = this.lock;
lock.lock();
try {
//获取原数组,并得出当前数组大小
Object[] elements = getArray();
int len = elements.length;
//获取旧值,并计算索引位置
E oldValue = get(elements, index);
int numMoved = len - index - 1;
//表示是末尾,直接拷贝原数组0-(len-1)
if (numMoved == 0)
setArray(Arrays.copyOf(elements, len - 1));
else {
//生成新数组并进行两次拷贝
Object[] newElements = new Object[len - 1];
System.arraycopy(elements, 0, newElements, 0, index);
System.arraycopy(elements, index + 1, newElements, index,
numMoved);
setArray(newElements);
}
return oldValue;
} finally {
//解锁
lock.unlock();
}
}
欠失は同様に、削除される要素以外の要素が新しい配列にコピーされ、新しいアレイへの参照を元の配列の参照点を切り替えます。書き込みに属している、あなたがロックする必要があります。
public E get(int index) {
return get(getArray(), index);
}
要素がロックされていない必要が取得します。
長所と短所
利点:
- CopyOnWriteArrayListと理由は、その「の孤立書き込み思考」、およびイテレータを横断するので、操作が演技異なるアレイを横断している修正し、それはConcurrentModificationExceptionが例外をスローしません。
- パフォーマンスを読むための任意の同期化対策なしで、より適切なので、非常に高く、あまり読み書き同時シーンを。
短所:
- メモリフットプリントの問題、元の容器のコピーであるためにその都度、書き込み動作、メモリ圧力に大量のデータは、頻繁にGCが発生することがあります。
- 適時性を保証することはできません、同期されている読み取りおよび書き込み操作のためのベクトルのロックを、あなたは強い一貫性が読み取りおよび書き込み確保することができます。CopyOnWriteArrayListとの実装戦略は、実行され、読み取りがブロックされませんが、それが更新されたデータに読み出され、書き込み動作時に、新旧の配列の異なる役割を、それぞれ、読み書きすることです。