2

まだそこにない場合は、マップに値を付ける必要があります。key->value (設定されている場合) は、常に 2 つのコレクションにある必要があります (つまりput、2 つのマップで原子的に発生する必要があります)。私はこれを次のように実装しようとしました:

private final ConcurrentMap<String, Object> map1 = new ConcurrentHashMap<String, Object>();
private final ConcurrentMap<String, Object> map2 = new ConcurrentHashMap<String, Object>();

public Object putIfAbsent(String key) {
    Object retval = map1.get(key);
    if (retval == null) {
        synchronized (map1) {
            retval = map1.get(key);
            if (retval == null) {
                Object value = new Object(); //or get it somewhere
                synchronized (map2) {
                    map1.put(key, value);
                    map2.put(key, new Object());
                }
                retval = value;
            }
        }
    }
    return retval;
}

public void doSomething(String key) {
    Object obj1 = map1.get(key);
    Object obj2 = map2.get(key);
    //do smth
}

それはすべての場合にうまくいきますか?ありがとう

4

4 に答える 4

0

わかりました、私はついにこの解決策に到達しました:

private Map<String, Object> map1 = new HashMap<String, Object>();
private Map<String, Object> map2 = new HashMap<String, Object>();

private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();

public void putIfAbsent(String key, Object o) {
    rwl.readLock().lock();
    try {
        if (map1.get(key) == null) {
            rwl.readLock().unlock();
            rwl.writeLock().lock();
            try {
                if (map1.get(key) == null) {
                    map1.put(key, getValue());
                    map2.put(key, getValue());
                }
            }finally {
                rwl.readLock().lock();
                rwl.writeLock().unlock();
            }
        }
    } finally {
        readLock.unlock();
    }
}

public void readMap(String key) {
   rwl.readLock().lock();
    try {
       Object obj1 = map1.get(key);
       Object obj2 = map2.get(key);
    } finally {
        rwl.readLock().unlock();
    }

}
于 2012-10-10T20:18:51.380 に答える
0

いくつかの問題:

  • 「ダブルチェックロック」を使用しないでください。Google で簡単に検索すると、この手法の問題点を説明する大量の記事が表示されます。synchronizedブロック内をチェックするだけです。
  • map1と の両方で同期する必要はありませんmap2。どちらか一方を使用してください。
  • 内で同期しますdoSomethingで同期に使用されるのと同じオブジェクトで同期していることを確認してくださいputIfAbsent
于 2012-10-08T21:34:52.933 に答える
0

Synchronized with ConcurrentHashMap は絶対に使用しないでください (目的をほとんど無効にしています)。CHH にアトミックな追加を行う最良の方法は、組み込みの replace メソッドを使用することです。例えば:

do {

    oldValue1 = map1.get(key1);
    oldValue2 = map2.get(key2);
    newValue1 = // some logic to determine a new value for key1/value1
    newValue2 = // some more logic to determine a new value for key2/value2

} while (!map1.replace(key1, oldValue1, newValue1) && !map2.replace(key2, oldValue2, newValue2));

これをあなたの例に具体的に適応させる方法はわかりませんが、これでどこかから始めることができます。基本的に何が起こるかというと、マップからキーを取得し、いくつかのロジックを実行します。キーがロジックの前と同じである場合、エントリが置き換えられて true が返され、ループが中断されます。それ以外の場合は、更新をアトミックに実行できるようになるまでループを繰り返します。

于 2012-10-08T21:38:56.053 に答える
-1

あなたが望むことをするために、私はアトミック参照を使用します:

class PairHolder {
   public final ConcurrentMap map1;
   public final ConcurrentMap map2;
   public PairHolder(...) // set values here.
}

private AtomicReference<PairHolder> mapHolder = ... // initialize it somehow

do {
  PairHolder holder = mapHolder.get();
  ConcurrentMap map1 = holder.map1.clone()
  ConcurrentMap map2 = holder.map2.clone()
  newMap1.putIfAbsent(...);
  newMap2.putIfAbsent(...);
} while (!mapHolder.compareAndSet(holder, new PairHolder(newMap1,newMap2))

このようにして、mapHolder に PairHolder への参照が含まれていることを常に確認できます。これにより、2 つのマップが 100% アトミックに更新されます。少なくとも CAS はこれを保証する必要がありますが、マルチプロセッサ システムでは間違っている可能性があります。

于 2012-10-08T22:10:28.940 に答える