0

実装では、次のコードを書きました。try-catch ブロックはメソッド内にあります

try{
    InputVals iv = task.getInputVals();
    Map<String, String> map = iv.getAllValues();
    String a = map.get("value1");
    String b = map.get("value2");
    String x = funcxy.methodGetX();
    String y = funcxy.methodGetY();
    iv.setValue(xval, x);
    iv.setValue(yval,y);

    String []names = {"name1", "name2", "name3"}
    for(int i = 0; i<names.length; i++ ){
         iv.setValue("name"+i, names[i] );
    }
  }

同時リクエストを数回 (常にではありません) 行うと、「java.util.ConcurrentModificationException: ハッシュマップへの同時アクセス」エラーがスローされます。使ってみた

Map<String, String> map= new ConcurrentHashMap<String, String>();
map = iv.getAllValues();

しかし、これは問題を解決しませんでした。どこで間違いを犯しているのか教えてください。の実装を変更できません

InputVals iv = task.getInputVals();
4

4 に答える 4

1

何を達成しようとしているのか完全にはわかりませんが、他の人がすでに指摘しているように、複数のスレッドiv.getAllValues()が同時に返されたマップを操作しようとしている可能性が高いため、例外がスローされます。

を使用してマップをコピーするとConcurrentHashMap、ローカル コピーから作業する場合と同じように機能します。ただし、そうすると、ローカルでのみ使用することになるため、提供される並行性チェックは必要ないことに注意してください。コードの問題は、データを実際に新しいマップにコピーしていないことです。あなたがする必要があったでしょう:

Map<String, String> map= new ConcurrentHashMap<String, String>( iv.getAllValues() );

マップ エントリを変更する際のニーズに応じて、最も簡単で最速の方法は、おそらくマップをコピーしてローカル コピーから作業することです。これにより、同時実行の問題が回避されます。もちろん、他のスレッドが更新された情報にアクセスする必要がある場合、この計画は機能しません。

try{
    InputVals iv = task.getInputVals();
    Map<String, String> map = new HashMap<String, String>();
    // copy all map values to a local var
    map.putAll( iv.getAllValues() );
    String a = map.get("value1");
    String b = map.get("value2");
    String x = funcxy.methodGetX();
    String y = funcxy.methodGetY();
    iv.setValue(xval, x);
    iv.setValue(yval,y);

    String []names = {"name1", "name2", "name3"}
    for(int i = 0; i<names.length; i++ ){
         iv.setValue("name"+i, names[i] );
    }
  }

synchronizedこれ以外では、マップへのすべての呼び出しがブロックで行われるようにする必要があります。ただし、このマップにアクセスするコード内にいくつかの異なる場所がある場合、これは非常に困難で退屈な場合があります。

于 2012-10-03T15:17:28.167 に答える
0

あなたは何をします InputVals.setValue()か?それはどのように定義されていますか?元の変数の参照を使用しているため、ビジネスロジックで ConcurrentHashMap を定義しても意味がありません。実際の Bean 自体に注意する必要があります。

以下のようなものであれば

Class Inputvals {
  Map<String, String> map = new HashMap <String,String>();
  public void setValue(String a,String b){
    map.put(a,b);
  }
  public Map<String,String> getAllValues(){
    return map;
  }
}

以下のように変更することをお勧めします

Class Inputvals {
  Map<String, String> map = new ConcurrentHashMap<String,String>();
  public void setValue(String a,String b){
    map.put(a,b);
  }
  ..
  ...

これは、マルチスレッド アクセスの問題を解決するのに役立ちます。

于 2012-10-04T05:06:01.480 に答える
0

getInputVals() によって返されるマップへのすべてのアクセスを同期する必要があります。別のスレッドのどこかで変更されています。以下のコードの行に沿って何かが必要になりますが、非常に重要なことは、現在変更されている場所を含め、このマップが使用されている他のすべての場所にもlockObjを適用する必要があることです (このコードは示されていません)。 .

try{
    InputVals iv = task.getInputVals();
    String a;
    String b;

    synchronized (lockOjb) {
        Map<String, String> map = iv.getAllValues();
        a = map.get("value1");
        b = map.get("value2");
    }
    String x = funcxy.methodGetX();
    String y = funcxy.methodGetY();
    iv.setValue(xval, x);
    iv.setValue(yval,y);

    String []names = {"name1", "name2", "name3"}
    for(int i = 0; i<names.length; i++ ){
         iv.setValue("name"+i, names[i] );
    }
  }

このコードを変更できるかどうかに応じて、これが可能な場合と不可能な場合があります。たとえば、ライブラリ内で既に発生している場合は、コードを再設計して、少なくともこのマップにアクセスする場所でマルチスレッド化しないようにする必要があります。

于 2012-10-03T15:04:06.407 に答える
-1

同期されたコレクションでマップをラップする必要がある場合があります

Map<String, String> map = Collections.synchronizedMap(iv.getAllValues());

次に、マップにアクセスします。

于 2012-10-03T13:08:22.320 に答える