インデックスによって要素にアクセスできるコンカレントリストインスタンスを作成するにはどうすればよいですか?JDKには、使用できるクラスまたはファクトリメソッドがありますか?
List
特にその元を破壊行為と見なされる要件です。回答がその破壊されたバージョンの質問に回答しないと不平を言っている人々のために、モデレーターはすでに質問をロックしました。
インデックスによって要素にアクセスできるコンカレントリストインスタンスを作成するにはどうすればよいですか?JDKには、使用できるクラスまたはファクトリメソッドがありますか?
List
特にその元を破壊行為と見なされる要件です。回答がその破壊されたバージョンの質問に回答しないと不平を言っている人々のために、モデレーターはすでに質問をロックしました。
回答:
java.util.concurrentには並行リストの実装があります。特にCopyOnWriteArrayList。
インデックスベースのアクセスを気にせず、リストの挿入順序を維持する特性だけが必要な場合は、java.util.concurrent.ConcurrentLinkedQueueを検討できます。Iterableを実装しているため、すべての項目の追加が完了したら、拡張されたfor構文を使用してコンテンツをループできます。
Queue<String> globalQueue = new ConcurrentLinkedQueue<String>();
//Multiple threads can safely call globalQueue.add()...
for (String href : globalQueue) {
//do something with href
}
:
のforeachと呼ばれている):docs.oracle.com/javase/1.5.0/docs/guide/language/foreach.html
単純な呼び出し同期が必要な場合は、Collections.synchronizedList(List)を使用できます。
List<Object> objList = Collections.synchronizedList(new ArrayList<Object>());
synchronizedList
は「同期」されますが、「同時」ではありません。多くのリスト操作(インデックスベース)は、それ自体がアトミックではなく、より大きな相互排除構造の一部である必要があるという1つの基本的な問題です。
Vector
は、よりも簡単ですCollections.synchronizedList(new ArrayList<Object>())
。
位置を取得し、指定された位置から要素を取得する動作には、当然、いくつかのロックが必要です(これらの2つの操作の間でリストに構造的な変更を加えることはできません)。
並行コレクションのまさにその考えは、それ自体の各操作はアトミックであり、明示的なロック/同期なしで実行できるということです。
したがって、アトミック操作としてn
特定の要素から位置に要素を取得することはList
、同時アクセスが予想される状況ではあまり意味がありません。
次のオプションがあります。
Collections.synchronizedList()
:あなたはどのラップすることができList
、実装(ArrayList
、LinkedList
またはサードパーティのリスト)。すべてのメソッド(読み取りと書き込み)へのアクセスは、を使用して保護されsynchronized
ます。iterator()
forループを使用または拡張する場合は、手動で同期する必要があります。反復中、他のスレッドは読み取りからも完全にブロックされます。hasNext
とのnext
呼び出しごとに個別に同期することもできますが、その場合ConcurrentModificationException
は可能です。
CopyOnWriteArrayList
:変更するにはコストがかかりますが、読むのに時間がかかります。イテレータがスローすることはなくConcurrentModificationException
、イテレータが作成中に別のスレッドによってリストが変更された場合でも、イテレータの作成時にリストのスナップショットを返します。頻繁に更新されないリストに役立ちます。のような一括操作addAll
は更新に適しています-内部配列のコピー回数は少なくなります。
Vector
:と非常によく似てsynchronizedList
いますが、反復も同期されます。ただし、反復中にConcurrentModificationException
ベクターが別のスレッドによって変更された場合、反復子はをスローできます。
別のオプション:
Collections.unmodifiableList()
:ロックフリー、スレッドセーフ、ただし変更不可Queue
またはDeque
、リストの最後にのみ追加/削除してリストを反復処理する場合は、代替手段になる場合があります。インデックスによるアクセスや、任意の場所での追加/削除はありません。パフォーマンスと同時アクセス性が向上した複数の同時実装がありますが、この質問の範囲を超えています。JCToolsを確認することもできます。JCToolsには、単一のコンシューマーまたは単一のプロデューサーに特化した、よりパフォーマンスの高いキュー実装が含まれています。CopyOnWriteArrayListは、基になる配列の新しいコピーを作成することによってすべての変更操作(追加、設定など)が実装されるArrayListのスレッドセーフなバリアントです。
CopyOnWriteArrayListは、同期されたListがListインターフェイスを実装し、java.util.concurrentパッケージとそのスレッドセーフコレクションの一部である並行処理の代替手段です。
public class CopyOnWriteArrayList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
CopyOnWriteArrayListはフェイルセーフであり、反復中に基になるCopyOnWriteArrayListが変更されたときにConcurrentModificationExceptionをスローしません。別のArrayListのコピーを使用します。
コピーアレイにはすべての更新操作が含まれるため、通常はコストがかかりすぎます。クローンコピーが作成されます。CopyOnWriteArrayListは、読み取り操作が頻繁に行われる場合にのみ最適です。
/**
* Returns a shallow copy of this list. (The elements themselves
* are not copied.)
*
* @return a clone of this list
*/
public Object clone() {
try {
@SuppressWarnings("unchecked")
CopyOnWriteArrayList<E> clone =
(CopyOnWriteArrayList<E>) super.clone();
clone.resetLock();
return clone;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError();
}
}