4

ConcurrentHashMapおよびこの関連するチュートリアルを行っていて、いくつか質問がありました。

  1. ConcurrentHashMapこの記事では、ブロックすることなく複数のリーダーが同時に読み取ることができると言及していました。これは、同時実行レベルに基づいてマップをさまざまな部分に分割し、更新中にマップの一部のみをロックすることによって実現されます。デフォルトの同時実行レベルは 16 であるため、Map は 16 の部分に分割され、各部分は異なるロックで管理されます。これは、Map の別の部分で動作するまで、16 個のスレッドが Map で同時に動作できることを意味します。これによりConcurrentHashMap、スレッド セーフが維持されているにもかかわらず、パフォーマンスが向上します。ただし、注意事項put()remove()ありputAll()ますclear()

  2. 記事でも言及されているもう 1 つのポイント:覚えておくべきもう 1 つの重要なポイントは、CHM の繰り返しです。返される Iterator はkeySet一貫性が弱くConcurrentHashMap、特定の時点での状態のみを反映し、最近の変更は反映されない可能性があります

太字で強調表示されている点が理解できませんでした。詳細情報を提供するか、簡単なプログラムを示してもらえますか?

4

2 に答える 2

2
  1. put()、remove()、putAll()、clear() などの更新操作は同期されないため、同時取得では Map の最新の変更が反映されない場合があります。

    私が理解しているように、これは、あるスレッドでのマップの変更が、別のスレッドで同時に行われる検索によって必ずしも見られるとは限らないことを意味します。次の例を検討してください。

                      Thread 1 starts              Thread 1's call to get("a")
                     a call to get("a")             completes, returning null
                             |                                 |
    Thread 1        ---------+---------------------------------+-------
                                 time ----->
    Thread 2        -----+---------------------------+-----------------
                         |                           |
                 Thread 2 starts a            Thread 2's call to
                call to put("a", 1)          put("a", 1) completes
    

    スレッド 2putがマップ内の値であるにもかかわらず、スレッド 1 のget実行が完了しましたが、スレッド 1 はマップの変更を「認識」せず、 を返しnullました。

  2. 覚えておくべきもう 1 つの重要な点は、CHM の反復です。ConcurrentHashMap の keySet によって返される Iterator は毎週一貫しており、ConcurrentHashMap の状態と特定のポイントのみを反映し、最近の変更を反映していない可能性があります。

    これは同様の状況です。スレッド 1がIteratorから を取得し、後でスレッド 2 が新しいエントリをマップに配置した場合、スレッド 1がそのエントリを参照することは保証されません。(あるかもしれないし、ないかもしれない。)ConcurrentHashMapkeySetIterator

于 2013-02-27T17:49:44.013 に答える
0

ここでの本当の問題は、複数のスレッドがデータ構造でだまされている場合、スレッドが必ずしもロック ステップで進行するとは限らないことです。

1 つのスレッドが user1 を読み取っています。1 つのスレッドが user2 に書き込みを行っています。どちらのスレッドも、それぞれのプロセスのどこに他のスレッドがあるかを予測できません。さらに、これら 2 つのプロセスの完了時にユーザーがどのような順序で処理されるかを予測することはできません。書き込みが最初にデータを更新する場合、user1 が少し前に読み取りを要求した可能性がある場合でも、読み取りは更新された状態を示します。

反復するときの読み取りまたは変更は、次のものに移動するプロセス (反復するとき) が基本的に Map の状態に対する "読み取り" 操作になるという追加の考慮事項と同じように機能します。 .

したがって、これらのデータ構造で同時実行を許可すると、時間に関して「十分に近い」テストになります。(これは、データベースの考え方に慣れていることと、時間枠が 10 分の 1 の係数であることを除いて、データベースに関する同じ考慮事項によく似ています。

注:別の回答で@Mattsが示した素晴らしい小さなタイムラインについてコメントするには...

タイムラインには、2 つのスレッドと、各スレッドの開始と停止が表示されます。2 つのスレッドの開始は、(a,b) または (b,a) のいずれかの順序で発生します。操作にかかる時間がわからないため、終了はどちらの順序でも発生する可能性があります。これにより、2 つのスレッドが開始および終了できる 4 つの方法が得られます。(a が最初に開始して最初に終了する、a が最初に開始して b が最初に終了する、b が最初に開始して a が最初に終了する、b が最初に開始して b が最初に終了する) さて ... 20 個のスレッドがすべて同じことを行っていると想像してください。あれやこれやのリクエストを送信する 20 人のエンド ユーザー。それが機能する可能性のある方法はいくつありますか。

于 2013-02-27T17:34:51.900 に答える