Javaコレクション:CopyOnWriteArrayListとSynchronizedList
8423 ワード
CopyOnWriteArrayList
まず2点を挙げます.
1.CopyOnWriteArrayListはjavaにある.util.concurrentパッケージの下で、このクラスは同時に設計されていることがわかります.
2、CopyOnWriteArrayList、その名の通り、Writeの場合は常にCopy、つまりCopyOnWriteArrayListに対して、任意の可変操作(add、set、removeなど)はコピーという動作を伴うものであり、後にCopyOnWriteArrayListの下位実装メカニズムを解読する
4つの注目点CopyOnWriteArrayListでの答え
注目点
結論
空の許可
はい
重複データの許可
はい
順序付け
秩序
スレッドのセキュリティ
安全
CopyOnWriteArrayListに要素を追加する方法
CopyOnWriteArrayListでは、追加、削除、修正、挿入の原理は同じなので、追加要素でCopyOnWriteArrayListの下位実装メカニズムを分析すればよい.
まずCopyOnWriteArrayListの構造を見てみましょう.
構築方法
CopyOnWriteArrayListの場合、最下位はObject[]arrayであり、次にCopyOnWriteArrayListがインスタンス化され、Object arrayは配列サイズ0の配列を指す.
要素の追加
要素を追加するたびに、CopyOnWriteArrayListは配列をコピーし、コストが非常に高いことがわかります.
読むときはロックをかける必要はなく、直接取得します.削除と追加にはロックが必要です.
2時に話さなければならないことがあります.CopyOnWriteArrayListという同時コンポーネントは、実は2つの非常に重要な分散理念を反映していると思います.
(1)読み書き分離
私たちがCopyOnWriteArrayListを読み込むときに読み取ったのはCopyOnWriteArrayListの中のObject[]arrayですが、修正するときに操作するのは新しいObject[]arrayで、読み書き操作は同じオブジェクトではなく、これが読み書き分離です.このような技術データベースは非常に多く使われており、高と下でデータベースの圧力を緩和するために、キャッシュをしてもデータベースを読み書き分離し、読むときはライブラリを使用し、書くときはライブラリを使用し、それからライブラリを読み、ライブラリを書く間で一定の同期を行うことで、同じライブラリで読み書きするIO操作が多すぎることを避けることができる.
(2)最終一致
CopyOnWriteArrayListでは,スレッド1が集合中のデータを読み取ることは,必ずしも最新のデータではない.スレッド2、スレッド3、スレッド4の4つのスレッドはいずれもCopyOnWriteArrayListの中のデータを修正しているが、スレッド1が入手したのはやはり最も古いObject[]arrayであり、新たに追加されたデータはないので、スレッド1が読み取った内容は必ずしも正確ではない.しかし、これらのデータはスレッド1に対しては一致しないが、その後のスレッドに対しては一致しているに違いない.それらが得たObject[]arrayは、3つのスレッドが動作した後のObject array[]に違いない.これが最終的な一致である.最終的な一貫性は分散システムにとっても重要であり、一定時間のデータの不一致を許容することによって、分散システム全体の可用性とパーティションフォールトトレランスを向上させる.もちろん、最終的な一致はいかなるシーンにも適用されるわけではありません.駅の切符販売のようなシステムのユーザーはデータのリアルタイム性に対する要求が非常に高く、強い一致性をしなければなりません.
最後に、CopyOnWriteArrayListの要素が増加するにつれて、CopyOnWriteArrayListの修正コストはますます高くなるので、CopyOnWriteArrayListは、修正操作よりも読み取り操作がはるかに多い同時シーンに適用される.
Collections.SynchronizedList
これはCollectionsの静的内部クラスであり、Collectionsの別の内部クラスであるSynchronizedCollectionsに継承されます.Collectionsを使用することができます.synchronizedList(List list)メソッドは、List可能なインスタンスを入力する必要があるため、非安全なListインスタンスを安全なListに変換することができる.
まず、SynchronizedCollectionの構造を見てみましょう.
その追加と削除方法に同期コードブロックを追加する
したがって、Collectionsクラスでは、同期コードブロックが単純に利用されており、元のスレッドが安全ではない集合であり、その内部クラスSynchronizedCollectionsを継承し、それぞれ独自の方法を書き換えてスレッドの安全を達成している.
まず2点を挙げます.
1.CopyOnWriteArrayListはjavaにある.util.concurrentパッケージの下で、このクラスは同時に設計されていることがわかります.
2、CopyOnWriteArrayList、その名の通り、Writeの場合は常にCopy、つまりCopyOnWriteArrayListに対して、任意の可変操作(add、set、removeなど)はコピーという動作を伴うものであり、後にCopyOnWriteArrayListの下位実装メカニズムを解読する
4つの注目点CopyOnWriteArrayListでの答え
注目点
結論
空の許可
はい
重複データの許可
はい
順序付け
秩序
スレッドのセキュリティ
安全
CopyOnWriteArrayListに要素を追加する方法
CopyOnWriteArrayListでは、追加、削除、修正、挿入の原理は同じなので、追加要素でCopyOnWriteArrayListの下位実装メカニズムを分析すればよい.
まずCopyOnWriteArrayListの構造を見てみましょう.
public class CopyOnWriteArrayList
implements List, RandomAccess, Cloneable, java.io.Serializable {
private static final long serialVersionUID = 8673264195747942595L;
/** The lock protecting all mutators */
final transient ReentrantLock lock = new ReentrantLock();
/** The array, accessed only via getArray/setArray. */
private transient volatile Object[] array;
.....
}
構築方法
/**
* Creates an empty list.
*/
public CopyOnWriteArrayList() {
setArray(new Object[0]);
}
/**
* Sets the array.
*/
final void setArray(Object[] a) {
array = a;
}
CopyOnWriteArrayListの場合、最下位はObject[]arrayであり、次にCopyOnWriteArrayListがインスタンス化され、Object arrayは配列サイズ0の配列を指す.
要素の追加
public boolean add(E e) {
final ReentrantLock lock = this.lock;
//
lock.lock();
try {
//
Object[] elements = getArray();
int len = elements.length;
// , +1
Object[] newElements = Arrays.copyOf(elements, len + 1);
//
newElements[len] = e;
//
setArray(newElements);
return true;
} finally {
//
lock.unlock();
}
}
要素を追加するたびに、CopyOnWriteArrayListは配列をコピーし、コストが非常に高いことがわかります.
読むときはロックをかける必要はなく、直接取得します.削除と追加にはロックが必要です.
2時に話さなければならないことがあります.CopyOnWriteArrayListという同時コンポーネントは、実は2つの非常に重要な分散理念を反映していると思います.
(1)読み書き分離
私たちがCopyOnWriteArrayListを読み込むときに読み取ったのはCopyOnWriteArrayListの中のObject[]arrayですが、修正するときに操作するのは新しいObject[]arrayで、読み書き操作は同じオブジェクトではなく、これが読み書き分離です.このような技術データベースは非常に多く使われており、高と下でデータベースの圧力を緩和するために、キャッシュをしてもデータベースを読み書き分離し、読むときはライブラリを使用し、書くときはライブラリを使用し、それからライブラリを読み、ライブラリを書く間で一定の同期を行うことで、同じライブラリで読み書きするIO操作が多すぎることを避けることができる.
(2)最終一致
CopyOnWriteArrayListでは,スレッド1が集合中のデータを読み取ることは,必ずしも最新のデータではない.スレッド2、スレッド3、スレッド4の4つのスレッドはいずれもCopyOnWriteArrayListの中のデータを修正しているが、スレッド1が入手したのはやはり最も古いObject[]arrayであり、新たに追加されたデータはないので、スレッド1が読み取った内容は必ずしも正確ではない.しかし、これらのデータはスレッド1に対しては一致しないが、その後のスレッドに対しては一致しているに違いない.それらが得たObject[]arrayは、3つのスレッドが動作した後のObject array[]に違いない.これが最終的な一致である.最終的な一貫性は分散システムにとっても重要であり、一定時間のデータの不一致を許容することによって、分散システム全体の可用性とパーティションフォールトトレランスを向上させる.もちろん、最終的な一致はいかなるシーンにも適用されるわけではありません.駅の切符販売のようなシステムのユーザーはデータのリアルタイム性に対する要求が非常に高く、強い一致性をしなければなりません.
最後に、CopyOnWriteArrayListの要素が増加するにつれて、CopyOnWriteArrayListの修正コストはますます高くなるので、CopyOnWriteArrayListは、修正操作よりも読み取り操作がはるかに多い同時シーンに適用される.
Collections.SynchronizedList
これはCollectionsの静的内部クラスであり、Collectionsの別の内部クラスであるSynchronizedCollectionsに継承されます.Collectionsを使用することができます.synchronizedList(List list)メソッドは、List可能なインスタンスを入力する必要があるため、非安全なListインスタンスを安全なListに変換することができる.
まず、SynchronizedCollectionの構造を見てみましょう.
static class SynchronizedCollection implements Collection, Serializable {
private static final long serialVersionUID = 3053995032091335093L;
final Collection c; // Backing Collection
final Object mutex; //
SynchronizedCollection(Collection c) {
this.c = Objects.requireNonNull(c);
// this
mutex = this;
}
.....
}
その追加と削除方法に同期コードブロックを追加する
public boolean add(E e) {
synchronized (mutex) {
return c.add(e);
}
}
public boolean remove(Object o) {
synchronized (mutex) {
return c.remove(o);
}
}
したがって、Collectionsクラスでは、同期コードブロックが単純に利用されており、元のスレッドが安全ではない集合であり、その内部クラスSynchronizedCollectionsを継承し、それぞれ独自の方法を書き換えてスレッドの安全を達成している.