0

以下のコード スニペットをスレッド セーフにする方法がわかりません。

class MapUser {
    Map<String,Integer> map = new ConcurrentHashMap<String,Integer>

    public void addToMap(String str, Integer val){
        if(checkMagicString(str)){
            map.put(str,val);
        }
    }

    private boolean checkMagicString(String str){
        //some logic to check Magic
        //this logic involved operation on the String parameter str i.e. subString,toCharArray etc
    }
}

メソッド addToMap は複数のスレッドによって同時に呼び出されることに注意してください。スレッドセーフが維持されていることを確認したい。ConcurrentHashMap を使用することで、スレッドが値を安全に追加することを保証できます。

しかし、メソッド checkMagicString(String str) がどのようにスレッドセーフなままでいられるのか理解できませんか? それを同期させる唯一の方法はありますか?それとも、呼び出し元メソッド addToMap を同期化する必要がありますか? checkMagicString メソッド内でマップにアクセスしていないことに注意してください。

4

2 に答える 2

2

checkMagicStringアトミックにしてもシーケンスにならない

if(checkMagicString(str)){
   map.put(str,val);
}

ifこれは、チェックとmap.put呼び出しの間でスレッドが中断される可能性があり、2 つのスレッドが同じ文字列を挿入することになる可能性があるためです。安全のために、シーケンス全体をロックする必要があります。

編集: 上記が許容される動作 (つまり、2 つのスレッドが同じキーを挿入して値を上書きする) でありcheckMagicString、共有状態で動作しない場合、コードはそのままで問題ありません。

于 2012-07-10T17:01:10.617 に答える
0

必要なのがアトミック操作である場合、このような場合に行う最善の方法は、checkMagicStrアトミックを確認し、マップ上でアトミック操作を使用することです。

boolean done = false;
while(!done) {
  Integer oldVal = map.get(str);
  if (checkMagicStr(str) {
    if (oldVal != null) {
      done = value == map.replace(str, val, oldVal); // otherwise try again...
    } else {
      done = null == map.putIfAbsent(str, val); // otherwise try again...
    }
  } else {
    done = true; // there's nothing to do...
  }
}

これは高度な並行システムで永久に実行される可能性があるため、whileループに制限を設け、ヒットした場合は例外をスローすることをお勧めします。あなたの質問から、なぜこれが必要なのかは明らかではありませんが、b / cあなたが持っているものは「スレッドセーフ」ですが、とにかくこれは役立つかもしれません。

于 2012-07-10T17:19:19.910 に答える