2010-12-04 9 views
4

コンカレント・ハッシュ・マップで現在の操作の場合、どのように安全な取得を実行しますか? (putIfAbsentのように同じもの)Java ConcurrentHashMapアトミック・ゲット(存在する場合)

悪い例、安全ではありません非常にスレッド(状況として作用し、その後チェック):

ConcurrentMap<String, SomeObject> concMap = new ... 

//... many putIfAbsent and remove operations 

public boolean setOption(String id, Object option){ 
    SomeObject obj = concMap.get(id); 

    if (obj != null){ 
     //what if this key has been removed from the map? 
     obj.setOption(option); 
     return true; 
    } 

    // in the meantime a putIfAbsent may have been called on the map and then this 
    //setOption call is no longer correct 

    return false; 
} 

はもう一つの悪い例は次のようになります。

public boolean setOption(String id, Object option){ 
     if (concMap.contains(id)){ 
      concMap.get(id).setOption(option); 
      return true; 
     } 
     return false; 
    } 

ここで望ましいものはでありそれらを同期させることによって、追加、削除、および操作をボトルネックにすることはありません。 containsKey/get、ちょうどgetを呼び出す

おかげ

+0

「このsetOption呼び出し」についてのご意見はありません。どのsetOptionメソッドを参照していますか?あなたのコードに2つあります。 –

+0

これはマップに格納されている一般的なオブジェクトの汎用的な設定メソッドです。 – cdmihai

+0

2つ目の例では、キーと値のペアがマップから削除される可能性があります。これは、包含テストと取得の間に起こる可能性があります。 –

答えて

1

あなたがしようとしているように見えるのは、複数の操作でキーをロックすることです。各操作はアトミックのみです。これは、キーをロックする単純な方法ではなく、マップをロックするだけです。

ただし、「キーを削除するとどうなるでしょうか?」というケースでは、setOptionが呼び出されるまで削除操作を遅らせるだけです。結果は同じでなければなりません。

あなたは解決する必要のない問題を解決しようとしているようです。キーが削除された後、またはキーが削除されるのを待っている間にsetOptionを呼び出すのが悪い理由を説明していません。 Javaの8以降、

private Striped<Lock> lock; 
    public boolean setOption(String id, Object option) { 
     try { 
     Lock lock = concMap.get(id); 
     lock.lock(); 
      if (concMap.contains(id)){ 
      concMap.get(id).setOption(option); 
     return true; 
    } 
    return false; 
     } finally { 
     lock.unlock(); 
     } 
    } 

または:あなたはのConcurrentMapで、単一のキーに複数の操作を行う必要がある場合

+0

ああ、あなたの返事をありがとう、私は自分の問題を理解した、それは単なる読者のライターの問題の修正されたケースです。並列に実行できるset1 = {op1、op2、op3 ...}の操作セットがあるとしますが、set2 = {opr1、opr2、..}の操作がset1からの最終操作を実行するたびに、 set2からの残りの操作は待たなければなりません。 – cdmihai

+0

@PeterLawreyは、私はまた、[ここ](http://stackoverflow.com/questions/41135998/how-to-atomically-update-the-value-of-concurrentmap-in-multithreaded-application)CHM上で同様の質問があります。スレッドセーフとアトミックな方法でconcurrenthashmapの値を更新しようとしています。 –

2

は使用しないでください。そのメソッドがnullを返し、キーが存在しなかった場合はキーが存在し、getの時刻にマップされた値が保持されています。ドキュメントから

:このマップがキーのマッピングを保持していない場合

は、指定されたキーがマッピングされている値を返し、またはnull。

これがあなたの第二の例は、どのように見えるべきかです:

public boolean setOption(String id, Object option) { 

    SomeObject opt = concMap.get(id); 
    if (opt == null) 
     return false; 

    opt.setOption(option); 
    return true; 
} 
+0

しかし、キーが存在しない呼び出し時にget呼び出しとそのテストの間にそのキーがマップに追加された(コード内の別のスレッドから)ため、getがnullを返すとどうなりますか? – cdmihai

+3

これは、ヌルテストの後にキーと値のペアを追加する他のスレッドとは概念的に違いますか? –

+0

値がブール値の場合はどうなりますか?ブール値をnullと比較することはできませんので、おそらくcontainsKeyを使用する必要があります。 –

6

ConcurrentHashMapget()方法がアトミックです。このマップはnull値を許可しないため、get()は「存在すれば取得」を実装します。結果がnullの場合、キーは存在しませんでした。

+0

しかし、キーが存在しなかったが、get呼び出し、それの戻り値のテストの間、そのキーが(コードのどこか、別のスレッドから)マップに追加されたため、通話時にnullを返します場合は何? – cdmihai

+0

キーが存在しない場合、getはnullを返します。しかし、getとnullテストの間に追加されていれば? – cdmihai

+0

返される値はマップ内で変更されただけで変更されません。 –

0

、あなたは競合を減らすために技術をストライピングロックのいずれかを使用することができ、ここではグアバの枠組みに例を示します:

concMap.compute(keyId, (key, value) -> { 
    dosmth; ... return key; }); 

PS:ConcurrentMap.computeは新しいアトミック方法であり、それはキーで行われる方法を確認可能なバリエーションは、ConcurrentMap.computeIfPresent()などです。

関連する問題