6

スレッドセーフを作成するために次の構成を使用していますMap

Collections.synchronizedMap(new LinkedHashMap());

エラーが発生していConcurrentModificationExceptionますが。

4

5 に答える 5

8

コードがなければ、本当の問題が何であるかを推測するのは難しいですが、私の推測では、返されたコレクションを使用して操作を実行していません。javadocによる

シリアルアクセスを保証するために、バッキングコレクションへのすべてのアクセスが返されたコレクションを介して実行されることが重要です。返されたコレクションを反復処理するときは、ユーザーが手動で同期する必要があります。

  Collection c = Collections.synchronizedCollection(myCollection);
     ...
  synchronized(c) {
      Iterator i = c.iterator(); // Must be in the synchronized block
      while (i.hasNext())
         foo(i.next());
  }

このアドバイスに従わないと、非決定論的な動作が発生する可能性があります。

于 2012-10-31T04:14:43.240 に答える
5

ここで他の回答を損なうことはありませんが、以下のこのコードは、同時変更が実際のマルチスレッドとはほとんど関係がないことを示しています。コレクションを反復処理しますが、反復中に変更すると発生します....

  List list = new ArrayList();
  list.add("1");
  list.add("2");

  Iterator i = list.iterator();
  while (i.hasNext()) {
      Object value = i.next();  // throws java.util.ConcurrentModificationException

      list.add("another");  
  }
于 2012-10-31T05:03:12.517 に答える
2

簡単にConcurrentModificationException言うと、コードで を取得しないための解決策は、 のConcurrentHashMap代わりに を使用することですCollections.synchronizedMap(new LinkedHashMap());。ここでの説明:

ナンバリが言うように、実際のコードがないと問題を特定するのは困難です。Mapこれは、含まれているオブジェクトのみを保護することに注意してください。それでも、メソッド内の同じオブジェクト インスタンスを変更できます。

Map<String, Object> map = new ConcurrentHashMap<String, Object();
//fill the map...
map.put("data", new Data());

//and now we have this unsynchronized method that two or more threads can access at the same time
public void modifyData(String key, int newDataIntValue) {
    //this is synchronized by the ConcurrentHashMap
    Data data = map.get(key);
    //this isn't
    //you can get problems here...
    data.setIntValue(newDataIntValue);
}

同期されたコレクションは、これらのケースのコードを保存しません。このメソッドは自分で同期する必要があります。

追加情報: キャッシュ ライブラリまたはFlyweight デザイン パターンを実装しようとしている場合は、車輪を再発明せず、ehcachejboss cacheなどの実証済みでテスト済みのフレームワークを使用してください。

于 2012-10-31T04:30:18.647 に答える
0

Javaドキュメントを見つけてください

指定されたマップに基づく同期 (スレッドセーフ) マップを返します。シリアル アクセスを保証するには、バッキング マップへのすべてのアクセスが、返されたマップを介して行われることが重要です。コレクション ビューのいずれかを反復処理する場合、返されたマップでユーザーが手動で同期することが不可欠です。

  Map m = Collections.synchronizedMap(new HashMap());
  ...
  Set s = m.keySet();  // Needn't be in synchronized block
  ...
  synchronized(m) {  // Synchronizing on m, not s!
      Iterator i = s.iterator(); // Must be in synchronized block
       while (i.hasNext())
          foo(i.next());
   }

このアドバイスに従わないと、非決定的な動作が発生する可能性があります。指定されたマップがシリアライズ可能な場合、返されるマップはシリアライズ可能になります。

パラメータ: m 同期されたマップに「ラップ」されるマップ。戻り値: 指定されたマップの同期ビュー。

于 2012-10-31T04:17:42.287 に答える
0

Synchronized は ConcurrentModificationException とは関係ありません。これは、リストの remove メソッドを使用してリストを繰り返し処理しているときにリスト項目を削除しようとすると、シングルスレッド環境で発生する可能性があるためです。

同期は、シリアル アクセスのみを保証します。

于 2015-08-07T06:44:42.253 に答える