2009-04-01 9 views
42

List <T>はスレッドセーフではないのはなぜですか?以下のサイトから

http://crfdesign.net/programming/top-10-differences-between-java-and-c

残念ながら、List<>はスレッドセーフではありません(C#のArrayListとJavaの Vectorは、スレッドセーフです)。 C#にはHashtableもあります。

List<T>はスレッドセーフではありません。 .NET Frameworkエンジニアの実装上の問題ですか?またはジェネリックスはスレッドセーフではありませんか?

+0

を使用することを提供します。 arraylist.aspx#threadSafetyToggle)と[List Of Of T](http://msdn.microsoft.com/en-us/library/6sh2ey19.aspx#threadSafetyToggle)は同じスレッドセーフティを持っています。 'ArrayList'は、[Synchronized](http://msdn.microsoft.com/en-us/library/system.collections.arraylist.synchronized.aspx)ラッパーを提供します。 –

答えて

67

実際には、JavaのVectorのタイプのスレッド安全性を分類する必要があります。 Javas Vectorはメソッド上で同期を使用するため、複数のスレッドから安全に使用できます。状態は損なわれません。

しかし、Javaのベクトルの有用性は、追加の同期化なしで複数のスレッドから制限されています。例えば、ベクター

Vector vector = getVector(); 
if (vector.size() > 0) { 
    object first = vector.get(0); 
} 

この方法は、ベクターの破損していない状態であろうが、それはまた正しくないから要素を読み取る単純な行為を考えます。 if文とget()の間で、別のスレッドがベクトルを変更するのを止めるものはありません。このコードは、競合状態のために最終的に失敗する可能性があります。

このタイプの同期は、少数のシナリオでのみ有効であり、確かに安くはありません。複数のスレッドを使用していない場合でも、同期のための目立つ価格を支払う。

.Netは、限られた有用性しか持たないシナリオでは、この価格をデフォルトで支払うことを選択しなかった。代わりに、ロックフリーリストを実装することを選択しました。作成者は同期を追加する責任があります。これはC++の "支払う金額"のモデルに近いです。

最近、Javaのベクトルなどの内部同期だけでコレクションを使用する危険性について、いくつかの記事を書いています。

  • A more usable API for a mutable thread safe collection
  • Why are thread safe collections so hard?

    +13

    小メモ:「ロックフリー」とは「ロックなしで同期」を意味し、「ロックなし」を意味しません。 http://en.wikipedia.org/wiki/Lock_free –

    +0

    私はStrilancと同意します:「ロックフリー」という用語を二重に使用しなければなりませんでした。 –

    +0

    「Count」のようなメソッドは、何かを気にしないことを決める目的で、スレッドセーフなコレクションで完全に合理的かつ合法的に使用できます。たとえば、キュ​​ーから取り出した2つの項目を使用していくつかの操作を実行する必要がある場合、完全に合理的なパターンは、プロパティを使用してカウントをチェックすることです(ロックではなく読み取りバリアを使用します)。ロックを取得してカウントを再度確認してください。まだ十分な場合は、操作を実行してください。それ以外の場合はスキップしてください。いずれにしてもロックを解除してください。 – supercat

    20

    なぜにするのですか?スレッドセーフなのでしょうか?すべてのクラスがそうではありません。実際、デフォルトでは、クラスはではなく、スレッドセーフです。

    スレッドセーフであるということは、リストを変更する操作が同時アクセスに対してインターロックされる必要があることを意味します。これは、単一のスレッドだけが使用するリストであっても必要です。それは非常に非効率的です。

    9

    それは単にスレッドセーフでないタイプを実装するための設計上の決定です。コレクションは、データ型を明示的に同期させるために、いくつかのコレクションで、ICollectionのプロパティSyncRootSynchronized()メソッドを提供します。

    SyncRootを使用して、マルチスレッド環境でオブジェクトをロックします。

    lock (collection.SyncRoot) 
    { 
        DoSomething(collection); 
    } 
    

    collection.Synchronized()を使用して、コレクションのスレッドセーフラッパーを取得します。

    +4

    JaredParの記事で、これがなぜあなたがしたいことではないのかについての説明を参照してください。 –

    2

    実際のスレッドの安全性については、List<>と他のコレクションタイプは不変である必要があります。 .NETへの並列拡張が.NET 4.0から出てくると、最も一般的に使用されるコレクションのスレッドセーフなバージョンが表示されます。 Jon Skeetこれにいくつか触れています。

    2

    競合状態の可能性JaredParの言及は、Vectorが想定しているスレッドセーフティに頼っている恐ろしい結果です。これは、「第9火曜日の毎週火曜日に、アプリケーションが変なことをする」という結果につながります。

    彼らはmodification of the collection while enumeratingシングルスレッドできますが、スレッドの安全性、時にはかなり大きなものが付属していますperformance hitがあります興味深い副作用と本当にスレッドセーフなコレクションcoming in .Net 4の数があります。

    フレームワークの開発者が行うべき論理的なことは、おそらくスレッドを実行していないユーザーの95%が可能な限りパフォーマンスを上げ、マルチスレッドを使用しているユーザーに依存しているそれを安全に保つために行うこと。

    0

    使用SynchronizedCollectionはまた、コンストラクタ-パラメータMSDN [ArrayListの(http://msdn.microsoft.com/en-us/library/system.collectionsによれば、共有同期:)

    関連する問題