スレッド セーフなコレクション
.NET Framework 4 では、スレッド セーフかつスケーラブルなコレクション クラスをいくつか含む System.Collections.Concurrent 名前空間が導入されています。 ユーザー コードで同期を追加することなく、複数のスレッドでこのようなコレクションの項目を安全かつ効率的に追加または削除できます。 新しいコードを記述する場合、コレクションに対して複数のスレッドが同時に書き込みを行うときは常に同時実行コレクション クラスを使用します。 共有コレクションの読み取りのみを行う場合は、System.Collections.Generic 名前空間のクラスを使用できます。 .NET Framework 1.1 以前のランタイムを対象にする必要がない場合は、1.0 コレクション クラスを使用しないことをお勧めします。
.NET Framework 1.0 と 2.0 のコレクションのスレッドの同期
.NET Framework 1.0 で導入されたコレクションは、System.Collections 名前空間にあります。 一般的に使用される ArrayList や Hashtable を含むこのコレクションは、コレクションのスレッド セーフ ラッパーを返す Synchronized
プロパティを通じてスレッド セーフを確保します。 このラッパーは、すべての追加操作または削除操作でコレクション全体をロックすることで機能します。 したがって、コレクションにアクセスしようとする各スレッドは、ロックを取得する順番を待機する必要があります。 これはスケーラブルではなく、大規模なコレクションの場合はパフォーマンスが大幅に低下するおそれがあります。 また、競合状態を完全に防ぐことはできません。 詳細については、「Synchronization in Generic Collections」 (ジェネリック コレクションでの同期) を参照してください。
.NET Framework 2.0 で導入されたコレクション クラスは、System.Collections.Generic 名前空間にあります。 これには、List<T>、Dictionary<TKey,TValue> などがあります。 これらのクラスを使用すると、.NET Framework 1.0 クラスと比較して、タイプ セーフおよびパフォーマンスが向上します。 ただし、.NET Framework 2.0 コレクション クラスではスレッドの同期は行われません。複数のスレッドで同時に項目を追加または削除する場合は、ユーザー コードですべての同期を行う必要があります。
.NET Framework 4 の同時実行コレクション クラスを使用することをお勧めします。このクラスは、.NET Framework 2.0 コレクション クラスのタイプ セーフを確保するだけでなく、.NET Framework 1.0 コレクションよりも効率的で完全なスレッド セーフも確保します。
粒度の細かいロック機構とロック制御の不要な機構
同時実行コレクション型には、.NET Framework 4 の新機能である SpinLock、SpinWait、SemaphoreSlim、CountdownEvent などの軽量な同期機構を使用するものもあります。 これらの同期型では、通常、スレッドを実際の待機状態にする前の短期間にビジー スピンが使用されます。 待機時間が非常に短くなると予測される場合は、スピンを使用すると、負荷がかかるカーネル遷移を伴う待機を行うよりも負荷が格段に小さくなります。 スピンを使用するコレクション クラスでは、この効率性は、複数のスレッドで項目を高速で追加および削除できることを意味します。 スピンとブロッキングの詳細については、「SpinLock」および「SpinWait」を参照してください。
ConcurrentQueue<T> クラスと ConcurrentStack<T> クラスでは、ロックは使用されません。 代わりに、Interlocked 操作によってスレッド セーフを確保します。
Note
同時実行コレクション クラスでは ICollection がサポートされるので、IsSynchronized プロパティと SyncRoot プロパティの実装が、これらのプロパティが無関係の場合でも提供されます。 IsSynchronized
は常に false
を返し、SyncRoot
は常に null
(Visual Basic の場合は Nothing
) になります。
System.Collections.Concurrent 名前空間に属するコレクション型を次の表に示します。
種類 | 説明 |
---|---|
BlockingCollection<T> | IProducerConsumerCollection<T> を実装する任意の型の境界ブロッキング機能を提供します。 詳細については、「BlockingCollection の概要」を参照してください。 |
ConcurrentDictionary<TKey,TValue> | キーと値のペアのディクショナリのスレッド セーフな実装。 |
ConcurrentQueue<T> | 先入れ先出し (FIFO: First In First Out) キューのスレッド セーフな実装。 |
ConcurrentStack<T> | 後入れ先出し (LIFO: Last In First Out) スタックのスレッド セーフな実装。 |
ConcurrentBag<T> | 要素の順序付けられていないコレクションのスレッド セーフな実装。 |
IProducerConsumerCollection<T> | BlockingCollection で使用するために型が実装する必要があるインターフェイス。 |
関連トピック
Title | 説明 |
---|---|
BlockingCollection の概要 | BlockingCollection<T> 型で提供される機能について説明します。 |
方法: ConcurrentDictionary の項目を追加および削除する | ConcurrentDictionary<TKey,TValue> の要素を追加および削除する方法について説明します。 |
方法: BlockingCollection の項目を個別に追加および取得する | 読み取り専用の列挙子を使用せずにブロッキング コレクションの項目を追加および取得する方法について説明します。 |
方法: 境界ブロッキング機能をコレクションに追加する | 任意のコレクション クラスを IProducerConsumerCollection<T> コレクションの基になるストレージ機構として使用する方法について説明します。 |
方法: ForEach を使用して BlockingCollection 内の項目を削除する | foreach (Visual Basic の場合は For Each ) を使用してブロッキング コレクションのすべての項目を削除する方法について説明します。 |
方法: パイプラインでブロッキング コレクションの配列を使用する | 複数のブロッキング コレクションを同時に使用してパイプラインを実装する方法について説明します。 |
方法: ConcurrentBag を使用してオブジェクト プールを作成する | 新しいオブジェクトを頻繁に作成する代わりにオブジェクトを再利用できるシナリオで、同時実行バッグを使用してパフォーマンスを向上させる方法について説明します。 |