スレッド セーフなコレクション
.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 プロパティを通じてスレッド セーフを確保します。 このラッパーは、すべての追加操作または削除操作でコレクション全体をロックすることで機能します。 したがって、コレクションにアクセスしようとする各スレッドは、ロックを取得する順番を待機する必要があります。 これはスケーラブルではなく、大規模なコレクションの場合はパフォーマンスが大幅に低下するおそれがあります。 また、競合状態を完全に防ぐことはできません。 詳細については、MSDN Web サイトの「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 操作によってスレッド セーフを確保します。
メモ |
---|
同時実行コレクション クラスでは ICollection がサポートされるので、IsSynchronized プロパティと SyncRoot プロパティの実装が、これらのプロパティが無関係の場合でも提供されます。IsSynchronized は常に false を返し、SyncRoot は常に null (Visual Basic の場合は Nothing) になります。 |
System.Collections.Concurrent 名前空間に属するコレクション型を次の表に示します。
型 |
説明 |
---|---|
IProducerConsumerCollection<T> を実装する任意の型の境界ブロッキング機能を提供します。 詳細については、「BlockingCollection の概要」を参照してください。 |
|
キーと値のペアのディクショナリのスレッド セーフな実装。 |
|
先入れ先出し (FIFO: First In First Out) キューのスレッド セーフな実装。 |
|
後入れ先出し (LIFO: Last In First Out) スタックのスレッド セーフな実装。 |
|
要素の順序付けられていないコレクションのスレッド セーフな実装。 |
|
BlockingCollection で使用するために型が実装する必要があるインターフェイス。 |
関連トピック
タイトル |
説明 |
---|---|
BlockingCollection<T> 型で提供される機能について説明します。 |
|
ConcurrentDictionary<TKey, TValue> の要素を追加および削除する方法について説明します。 |
|
読み取り専用の列挙子を使用せずにブロッキング コレクションの項目を追加および取得する方法について説明します。 |
|
任意のコレクション クラスを IProducerConsumerCollection<T> コレクションの基になるストレージ機構として使用する方法について説明します。 |
|
foreach (Visual Basic の場合は For Each) を使用してブロッキング コレクションのすべての項目を削除する方法について説明します。 |
|
複数のブロッキング コレクションを同時に使用してパイプラインを実装する方法について説明します。 |
|
新しいオブジェクトを頻繁に作成する代わりにオブジェクトを再利用できるシナリオで、同時実行バッグを使用してパフォーマンスを向上させる方法について説明します。 |