web-dev-qa-db-ja.com

Java並行性:CAS vsロック

私は本を​​読んでいますJavaの並行性の実践。第15章では、ノンブロッキングアルゴリズムとcompare-and-swap(CAS)メソッドについて説明しています。

CASはロック方式よりもはるかに優れたパフォーマンスを発揮すると書かれています。 これらの概念の両方で既に働いている人々に尋ねたいです、そして、あなたがこれらの概念のどちらを好むかについて聞きたいですか?それは本当にずっと速いですか?

私にとって、ロックの使用法ははるかに明確で理解しやすく、おそらく維持するのがより良いでしょう(間違っている場合は私を修正してください)。パフォーマンスを向上させるために、ロックよりもCASに関連する同時コードの作成に本当に焦点を当てるべきですか、それとも持続可能性がより重要ですか?

何を使用するかについて、厳密な規則がないかもしれません。 ただし、CASの新しい概念に関する意見や経験を聞きたいと思います。

69
Prine

CASは一般にロックよりもはるかに高速ですが、競合の程度に依存します。 CASは読み取りと比較の間で値が変わると再試行を強制する可能性があるため、問題の変数が他の多くのスレッドによって激しくヒットされている場合(または新しい値を計算するのに費用がかかる場合)、スレッドは理論的にビジー待機でスタックする可能性があります古い値から(または両方))。

CASの主な問題は、ロックよりも正確にプログラムするのがはるかに難しいことです。念のため、ロックはメッセージの受け渡しや [〜#〜] stm [〜#〜] よりも適切に使用するのがはるかに難しいので、これをリンギングの承認として受け取らないでください。ロックの使用。

41
Marcelo Cantos

操作の相対速度は、ほとんど問題ではありません。関連するのは、ロックベースのアルゴリズムとノンブロッキングアルゴリズムのスケーラビリティの違いです。また、1つまたは2つのコアシステムで実行している場合は、そのようなことを考えるのをやめてください。

ノンブロッキングアルゴリズムは、ロックベースのアルゴリズムよりも「クリティカルセクション」が短いため、一般にスケーラビリティが向上します。

28
Brian Goetz

ConcurrentLinkedQueueBlockingQueueの間の数字を見ることができます。表示されるのは、[〜#〜] cas [〜#〜]が中程度(実際のアプリケーションではより現実的)なスレッド競合で顕著に速いことです。

nonblockingアルゴリズムの最も魅力的な特性は、1つのスレッドが失敗すると(キャッシュミス、またはさらに悪いことに、セグフォールト)、他のスレッドはこれに気付かないという事実です失敗し、先に進むことができます。ただし、ロックを取得するときに、ロック保持スレッドに何らかのOS障害が発生すると、ロックの解放を待機している他のすべてのスレッドにも障害が発生します。

質問に答えるために、はい、ノンブロッキングスレッドセーフアルゴリズムまたはコレクション(ConcurrentLinkedQueueConcurrentSkipListMap/Set)は、対応するブロックよりも大幅に高速です。 Marceloが指摘したように、ノンブロッキングアルゴリズムを正しく取得することは非常に難しく、多くの考慮が必要です。

Michael and Scott Queue について読む必要があります。これはConcurrentLinkedQueueのキュー実装であり、2つの方法、スレッドセーフ、アトミック関数を単一の[〜#〜] cas [〜#〜]

22
John Vint

ロックフリーの同時実行性のトピックに強く関連する良い本があります:Maurice Herlihyによる "The Art of multi-processor programming"

13
Victor Sorokin

実世界の比較を探しているなら、ここに一つあります。このアプリケーションには2つのスレッドがあります。1)ネットワークパケットキャプチャ用のリーダースレッドと、2)パケットを取得してカウントし、統計を報告するコンシューマスレッドです。

スレッド#1は一度に1つのパケットをスレッド#2と交換します

結果#1-クラスがCASSynchronousQueueと呼ばれるSynchronousQueueと同じ原則を使用して、カスタムCASベースの交換を使用します。

30,766,538 packets in 59.999 seconds ::  500.763Kpps, 1.115Gbps 0 drops
libpcap statistics: recv=61,251,128, drop=0(0.0%), ifdrop=0

結果#2-CAS実装を標準のJava SynchronousQueueに置き換えた場合:

8,782,647 packets in 59.999 seconds ::  142.950Kpps, 324.957Mbps 0 drops 
libpcap statistics: recv=69,955,666, drop=52,369,516(74.9%), ifdrop=0

パフォーマンスの違いがこれ以上明確になるとは思いません。

8
Mark Bednarczyk