it.next()がjava.util.ConcurrentModificationExceptionをスローするのはなぜですか?

いいね:
final Multimap<Term, BooleanClause> terms = getTerms(bq);
        for (Term t : terms.keySet()) {
            Collection<BooleanClause> C = new HashSet(terms.get(t));
            if (!C.isEmpty()) {
                for (Iterator<BooleanClause> it = C.iterator(); it.hasNext();) {
                    BooleanClause c = it.next();
                    if(c.isSomething()) C.remove(c);
                }
            }
        }

SSCCEではありませんが、においを拾うことができますか?

Vineet Reynolds:

Iterator以下のためのHashSetクラスは、フェイルファスト反復子です。HashSetクラスのドキュメントから

このクラスのイテレータメソッドによって返されるイテレータはフェイルファストです。イテレータが作成された後、イテレータ自身のremoveメソッド以外の方法でセットが変更されると、イテレータはConcurrentModificationExceptionをスローします。したがって、同時変更に直面した場合、イテレーターは、将来の不確定な時点で任意の非決定論的な動作のリスクを冒すのではなく、迅速かつクリーンに失敗します。

イテレータのフェイルファスト動作は、一般的に言えば、非同期の同時変更が存在する場合にハードな保証を行うことが不可能であるため、保証できないことに注意してください。フェイルファーストイテレータは、ベストエフォートベースでConcurrentModificationExceptionをスローします。したがって、この例外に依存して正確であるプログラムを作成するのは誤りです。反復子のフェイルファスト動作は、バグを検出するためだけに使用する必要があります。

最後の文に注意してください-キャッチしているという事実ConcurrentModificationExceptionは、別のスレッドがコレクションを変更していることを意味します。同じJavadoc APIページにも次のように記載されています。

複数のスレッドがハッシュセットに同時にアクセスし、少なくとも1つのスレッドがセットを変更する場合は、外部で同期する必要があります。これは通常、セットを自然にカプセル化するいくつかのオブジェクトで同期することによって行われます。そのようなオブジェクトが存在しない場合は、Collections.synchronizedSetメソッドを使用してセットを「ラップ」する必要がありますこれは、セットへの偶発的な非同期アクセスを防ぐために、作成時に行うのが最適です。

Set s = Collections.synchronizedSet(new HashSet(...));

Javadocへの参照は、次に何をすべきかについて自明であると思います。

さらに、あなたの場合、オブジェクトにImmutableSetHashSetを作成する代わりに、なぜそれを使用していないのかわかりませんterms(これは、途中で変更される可能性があります。getTermsメソッドの実装を確認することはできませんが、基になるキーセットが変更されています)。不変セットを作成すると、現在のスレッドが元のキーセットの独自の防御コピーを持つことができます。

ConcurrentModificationException(Java APIドキュメントに記載されているように)同期セットを使用することで防止できますが、すべてのスレッドが同期コレクションにアクセスし、バッキングコレクションに直接アクセスしないことが前提条件であることに注意してください(これは、HashSetの基になるコレクションMultiMapは他のスレッドによって変更されますが、おそらく1つのスレッドで作成されます同期されたコレクションクラスは、スレッドがアクセスを取得するための内部ミューテックスを実際に維持します。他のスレッドから直接mutexにアクセスすることはできないため(そして、ここではそうするのはかなり馬鹿げているでしょう)、クラスのメソッドを使用して、キーセットまたはMultiMap自体の防御コピーを使用することを検討する必要があります。unmodifiableMultimapMultiMaps(getTermsメソッドから変更不可能なMultiMapを返す必要があります)。同期されたMultiMapを返す必要性を調査することもできますが、その場合も、基礎となるコレクションを同時変更から保護するために、任意のスレッドがミューテックスを取得する必要があることを確認する必要があります。

実際のコレクションへの同時アクセスが保証されるかどうかがわからないという唯一の理由で、スレッドセーフのHashSet使用について言及することを意図的に省略していますほとんどの場合そうではありません。


編集:ConcurrentModificationExceptions Iterator.nextシングルスレッドシナリオでスローされます

これはif(c.isSomething()) C.remove(c);、編集された質問で導入されたステートメントに関するものです。

呼び出しCollection.removeによって質問の性質が変わりConcurrentModificationExceptionます。シングルスレッドのシナリオでもsをスローできるようになったためです。

可能性は、Collectionの反復子の使用と組み合わせてメソッド自体を使用することから発生します。この場合it、ステートメントを使用して初期化された変数ですIterator<BooleanClause> it = C.iterator();

Iterator itその繰り返し処理オーバーCollection Cの現在の状態に保存状態の関連Collectionこの特定のケース(Sun / Oracle JREを想定)では、KeyIteratorHashMapで使用されるクラスの内部内部クラスHashSet)を使用してを反復処理しますCollectionこれの特定の特徴Iteratorは、そのメソッドを介してCollectionHashMapこの場合)で実行された構造変更の数を追跡することIterator.removeです。

直接呼び出しremoveCollection後、の呼び出しで追跡するとIterator.next、反復子はをスローし、が認識していないの構造変更が発生したかどうかConcurrentModificationExceptionIterator.next確認します。この場合は、によって追跡されますがによって追跡されない構造変更が発生ます。CollectionIteratorCollection.removeCollectionIterator

問題のこの部分を克服するには、ではなくを呼び出す必要がIterator.removeあります。Collection.removeこれにより、Iteratorがへの変更を認識できるようになりCollectionます。Iteratorこの場合には、を介して発生する構造的な変更追跡するremove方法。したがって、コードは次のようになります。

final Multimap<Term, BooleanClause> terms = getTerms(bq);
        for (Term t : terms.keySet()) {
            Collection<BooleanClause> C = new HashSet(terms.get(t));
            if (!C.isEmpty()) {
                for (Iterator<BooleanClause> it = C.iterator(); it.hasNext();) {
                    BooleanClause c = it.next();
                    if(c.isSomething()) it.remove(); // <-- invoke remove on the Iterator. Removes the element returned by it.next.
                }
            }
        }

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

java.util.ConcurrentModificationExceptionが発生するのはなぜですか?

分類Dev

JavaでStackを使用してjava.util.ConcurrentModificationExceptionが発生するのはなぜですか?

分類Dev

java.util.concurrent.TimeUnit.convertが抽象ではなくAbstractMethodErrorをスローするのはなぜですか

分類Dev

java.util.concurrent.TimeUnit.convertが抽象ではなくAbstractMethodErrorをスローするのはなぜですか

分類Dev

プログラムがjava.util.InputMismatchExceptionをスローするのはなぜですか?

分類Dev

Executors.newCachedThreadPoolが送信中にjava.util.concurrent.RejectedExecutionExceptionをスローするのはなぜですか

分類Dev

java.util.Randomがマスクを使用するのはなぜですか?

分類Dev

このコードでjava.util.InputMismatchExceptionがスローされるのはなぜですか?

分類Dev

Iterator next()とremove()を使用する次のコードがConcurrentModificationExceptionをスローするのはなぜですか?

分類Dev

なぜこのコードはjava ConcurrentModificationExceptionをスローするのですか?

分類Dev

Javaスキャナーのnext( "。")がjava.util.InputMismatchExceptionを返す

分類Dev

この例でjava.util.ConcurrentModificationExceptionが返されないのはなぜですか?

分類Dev

java.util.Collectionがnext()、hasNext()を直接定義しないのはなぜですか?

分類Dev

Javaリスナーはjava.util.EventListenerを継承する必要があります-なぜですか?

分類Dev

スキャナーを使おうとすると、なぜjava.util.NoSuchElementExceptionが発生するのですか?

分類Dev

スレッド「main」java.util.ConcurrentModificationExceptionの例外を修正するにはどうすればよいですか。

分類Dev

java.util.CalendarクラスがAndroidで間違った日付を表示するのはなぜですか?

分類Dev

java.util.Observableが抽象クラスではないのはなぜですか?

分類Dev

java.util.ConcurrentModificationException-(リストではなく)IO操作を実行するときのバグ

分類Dev

Java11がjava.util.zip.ZipFile $ Sourceをヒープ上に保持しているのはなぜですか?

分類Dev

java.util.loggingを使用しないのはなぜですか?

分類Dev

Java:java.util.Collections.list(Enumeration)が破壊的であるのはなぜですか?

分類Dev

java.util.InputMismatchExceptionの問題が発生するのはなぜですか?

分類Dev

サンプルがConcurrentModificationExceptionをスローしないのはなぜですか

分類Dev

java.util.PropertiesがHashtable <String、String>ではなくHashtable <Object、Object>を拡張するのはなぜですか?

分類Dev

リストに追加するとjava.util.ConcurrentModificationExceptionがスローされます

分類Dev

java.util.logging.Loggerがstderrに出力するのはなぜですか?

分類Dev

リンクリストではなく配列を使用するjava.util.concurrent.PriorityBlockingQueueがなぜですか

分類Dev

イコールがjava.util.Comparatorに実装する必要がないのはなぜですか?

Related 関連記事

  1. 1

    java.util.ConcurrentModificationExceptionが発生するのはなぜですか?

  2. 2

    JavaでStackを使用してjava.util.ConcurrentModificationExceptionが発生するのはなぜですか?

  3. 3

    java.util.concurrent.TimeUnit.convertが抽象ではなくAbstractMethodErrorをスローするのはなぜですか

  4. 4

    java.util.concurrent.TimeUnit.convertが抽象ではなくAbstractMethodErrorをスローするのはなぜですか

  5. 5

    プログラムがjava.util.InputMismatchExceptionをスローするのはなぜですか?

  6. 6

    Executors.newCachedThreadPoolが送信中にjava.util.concurrent.RejectedExecutionExceptionをスローするのはなぜですか

  7. 7

    java.util.Randomがマスクを使用するのはなぜですか?

  8. 8

    このコードでjava.util.InputMismatchExceptionがスローされるのはなぜですか?

  9. 9

    Iterator next()とremove()を使用する次のコードがConcurrentModificationExceptionをスローするのはなぜですか?

  10. 10

    なぜこのコードはjava ConcurrentModificationExceptionをスローするのですか?

  11. 11

    Javaスキャナーのnext( "。")がjava.util.InputMismatchExceptionを返す

  12. 12

    この例でjava.util.ConcurrentModificationExceptionが返されないのはなぜですか?

  13. 13

    java.util.Collectionがnext()、hasNext()を直接定義しないのはなぜですか?

  14. 14

    Javaリスナーはjava.util.EventListenerを継承する必要があります-なぜですか?

  15. 15

    スキャナーを使おうとすると、なぜjava.util.NoSuchElementExceptionが発生するのですか?

  16. 16

    スレッド「main」java.util.ConcurrentModificationExceptionの例外を修正するにはどうすればよいですか。

  17. 17

    java.util.CalendarクラスがAndroidで間違った日付を表示するのはなぜですか?

  18. 18

    java.util.Observableが抽象クラスではないのはなぜですか?

  19. 19

    java.util.ConcurrentModificationException-(リストではなく)IO操作を実行するときのバグ

  20. 20

    Java11がjava.util.zip.ZipFile $ Sourceをヒープ上に保持しているのはなぜですか?

  21. 21

    java.util.loggingを使用しないのはなぜですか?

  22. 22

    Java:java.util.Collections.list(Enumeration)が破壊的であるのはなぜですか?

  23. 23

    java.util.InputMismatchExceptionの問題が発生するのはなぜですか?

  24. 24

    サンプルがConcurrentModificationExceptionをスローしないのはなぜですか

  25. 25

    java.util.PropertiesがHashtable <String、String>ではなくHashtable <Object、Object>を拡張するのはなぜですか?

  26. 26

    リストに追加するとjava.util.ConcurrentModificationExceptionがスローされます

  27. 27

    java.util.logging.Loggerがstderrに出力するのはなぜですか?

  28. 28

    リンクリストではなく配列を使用するjava.util.concurrent.PriorityBlockingQueueがなぜですか

  29. 29

    イコールがjava.util.Comparatorに実装する必要がないのはなぜですか?

ホットタグ

アーカイブ