2012-02-09 12 views
3

私は(名前が類推の目的のために不自然です)私は、次の動作を実装できることを使用する1つ以上の同時コレクションを見つけようとしている:のjava:同時コレクション

/** 
* Acts as a broker for a concurrent hash map that stores its keys in order 
* of submission. At shipping time, the concurrent map is "sealed" 
* (picture a truck with its cargo door being closed) 
* and its contents presented as an immutable map, and is replaced 
* by a new concurrent map ready to accept values. 
* 
* Consumers of this class that submit information to it, are expected to 
* know that this contains a concurrent collection, and should use the 
* compareAndSet paradigm, e.g. the following: 
* 
* LoadingDock loadingDock = ... 
* boolean done = false; 
* while (!done) 
* { 
* V oldValue = loadingDock.get(); 
* V newValue = computeNewValue(oldValue, otherInformation); 
* if (oldValue == null) 
*  done = loadingDock.putIfAbsent(newValue) == null; 
* else 
*  done = loadingDock.replace(oldValue, newValue) == oldValue; 
* } 
*  
* 
* Keys and values must be non-null. Keys are not ordered. 
*/ 
class LoadingDock<K,V> 
{ 
    /** 
    * analogous to ConcurrentMap's replace, putIfAbsent, and get methods 
    */ 
    public boolean replace(K key, V oldValue, V newValue); 
    public V putIfAbsent(K key, V value); 
    public V get(K key) 

    /* see above */ 
    public Map<K,V> ship(); 
} 

私は2つの問題を抱えていますこれとともに。

JavaとGuavaのどちらにもConcurrentLinkedHashMapが含まれていないことが1つあります。これはなぜ私がそのような獣の微妙なものを見逃しているのか不思議に思います。 putIfAbsent()が呼び出されてnullを返す場合、リストにキーを追加するクラスでConcurrentHashMapをデコレートすることで自分自身を作ることができるようです - ConcurrentHashMapで上記以外のメソッドは必要ありませんが、 putIfAbsent()への呼び出しを除いて、マップに新しいキーを追加する方法はありません。

ship()を実装する方法を考えることができないということです。ship()が呼び出されたときに、LoadingDockはすべての新しい呼び出しを新しいマップに指示する必要があります。並行書込みがすべて完了するまで古いマップを戻すことはできません。 (そうでなければ、AtomicReferenceを使用して同時マップを保持しています)

これを同期させる必要はありませんか?

+0

私は今は 'synchronized'でこれを行い、パフォーマンスが問題であれば後で最適化を試みるべきだと思っています...問題は私が期待するところです。 –

+1

同期なしで並行処理を処理する良い方法の1つは、aakaライブラリhttp://akka.io/downloads/を使用することです。Javaコードからaakaライブラリを使用できます。また、スカラーアクターライブラリを使用することもできます。 – Masa

答えて

5

ConcurrentSkipListMapを使用し、タイムスタンプに基づいてエントリをソートする独自のコンパレータを用意することができます。 ConcurrentLinkedMapはないと想像してください。なぜなら、それを実装する特に良い方法はないからです。通常の同期と比べてはるかに優れています。

fair()モードを有効にしたReadWriteLockを使用してください。マップに追加したいスレッドは、読み込みロック(私が知っている奇妙なセマンティクスを取得しますが、それはどのように動作するのか、それをマップへの実際の参照のための読み込みモードと考えることができます。同じ時間に追加することができます。 shipメソッドでは、書き込みロックを取得し、新しいマップをエクスポートして作成する間に他の誰かがマップを変更するのをブロックします。フェアモードを使うと、可能な限りclose()が呼び出され、既存のものが終了するようにaddersをできるだけ近くにカットするようになります。

+0

このようにReadWriteLockを使用する "後方"のセマンティクスを拡張できますか?私は理解していると思うが、私は100%確実ではない。 ConcurrentMapはConcurrentMapを使用しているので、ConcurrentMapは並行性を処理するため、 'putIfAbsent()'や 'get()'や 'replace()'を競合せずに呼び出すことができます。一方、それらのメソッドへの進行中の呼び出しは、 'ship()'への呼び出しと相互排他的であり、 'ship()'への呼び出しは他の 'ship()'呼び出しと相互に排他的です。 read()操作とwrite()操作は同形です。しかし、私は完全には確実ではない。 –

+1

です。私はこれを教えようとした最後の人は本当に混乱していました。私はなぜマップに値を書きたいときに '読み込み'ロックを取得するように指示していたのですか? '地図のための読み取り専用ロック'と考えるのではなく、地図へのポインタをロックする必要があります。 – Affe

+0

ああ。それは理にかなっている。明確にするために私がしたのは、 'final private Lock 'でした。mapUsageLock = this.lock.readLock();最終的なプライベートロックmapSwapLock = this.lock.writeLock(); 'マップを新しいマップに変更することを、(共有できる)使い方と区別するために使用します。 –

関連する問題