3

ConcurrentHashMap一貫したイテレータを提供するために「スナップショット」をサポートする を作成しようとしていますが、これを行うためのより効率的な方法があるかどうか疑問に思っています。問題は、2 つの反復子が同時に作成された場合、それらは同じ値を読み取る必要があり、同時ハッシュ マップの弱整合性反復子の定義は、これが当てはまることを保証しないことです。また、可能であればロックも避けたいと思います。マップには数千の値があり、各アイテムの処理には数十ミリ秒かかります。この間にライターをブロックする必要はありません。分以上。

私がこれまでに持っているもの:

  1. キーは文字列で、そのConcurrentHashMap's値はのインスタンスですConcurrentSkipListMap<Long, T>
  2. を使用してハッシュマップに要素が追加されるとputIfAbsent、新しいスキップリストが割り当てられ、オブジェクトが を介して追加されskipList.put(System.nanoTime(), t)ます。
  3. マップをクエリするには、map.get(key).lastEntry().getValue()最新の値を返すために使用します。スナップショットを (たとえばイテレータを使用して) クエリするには、 を使用しますmap.get(key).lowerEntry(iteratorTimestamp).getValue()。ここで、はイテレータが初期化されたときに呼び出されたiteratorTimestamp結果です。System.nanoTime()
  4. オブジェクトが削除された場合、map.get(key).put(timestamp, SnapShotMap.DELETED)DELETED が静的な最終オブジェクトである を使用します。

質問:

  1. すでにこれを実装しているライブラリはありますか? ConcurrentHashMapまたはそれを除いて、およびよりも適切なデータ構造はありConcurrentSkipListMapますか? 私のキーは同等なので、おそらくある種の同時ツリーは、同時ハッシュテーブルよりもスナップショットをより適切にサポートするでしょう。
  2. このことが継続的に成長するのを防ぐにはどうすればよいですか? X より前に初期化されたすべての反復子が完了した後、X より小さいキー (マップ内の最後のキーを除く) を持つすべてのスキップ リスト エントリを削除できますが、いつ削除するかを判断する良い方法がわかりません。メソッドが false を返したときにイテレータが完了したことを示すフラグを立てることができhasNextますが、必ずしもすべてのイテレータが完了まで実行されるとは限りません。ガベージ コレクションがいつ行われたかを検出できるように、WeakReferenceto をイテレータに保持できますが、弱い参照のコレクションを反復処理してから数回スリープするスレッドを使用する以外に、これを検出する良い方法が思いつきません。分 - 理想的には、スレッドはWeakReferenceラップされた参照がGCされたときに通知されますが、これはオプションではないと思います.

    ConcurrentSkipListMap<Long, WeakReference<Iterator>> iteratorMap;
    while(true) {
        long latestGC = 0;
        for(Map.Entry<Long, WeakReference<Iterator>> entry : iteratorMap.entrySet()) {
            if(entry.getValue().get() == null) {
                iteratorMap.remove(entry.getKey());
                latestGC = entry.getKey();
            } else break;
        }
        // remove ConcurrentHashMap entries with timestamps less than `latestGC`
        Thread.sleep(300000); // five minutes
    }
    

編集:回答とコメントの混乱を解消するために、現在、一貫性の低いイテレータを社内の別の部門によって記述されたコードに渡しています。イテレータの一貫性の強度を高めるように求められています。彼らは、私が 100% 一貫性のある反復子を作成することは不可能であることをすでに認識しており、私の側で最善の努力をしたいと考えています。彼らはイテレータの一貫性よりもスループットに関心があるため、粗粒度のロックはオプションではありません。

4

3 に答える 3

0

解決策 1) puts と iteration で同期するだけです。これにより、一貫したスナップショットが得られるはずです。

解決策 2) 反復を開始し、そのようにブール値を作成してから、putAll をオーバーライドしてキューに入れるようにします。反復が終了したら、単に変更された値でそれらの put を作成します。

于 2013-05-17T03:01:54.647 に答える