0

Java でマルチスレッド チャットを作成しています。ユーザー u1 がユーザー u2 にメッセージを送信したが、ユーザー u2 が接続されていない場合、ユーザー u1 はメッセージをサーバーに送信し、ユーザー u2 はサーバーに接続するとメッセージを受信します。送信されないメッセージは ArrayList に追加されます。ユーザーが接続すると、保留中のメッセージの受信者かどうかを確認します。彼がいる場合、メッセージは彼に送信され、保留中のメッセージ リストから削除されます。これは私がそれを行う方法です:

for(Iterator<String> itpendingmsgs = pendingmsgs.iterator(); itpendingmsgs.hasNext();) {
    String pendingmsg = itpendingmsgs.next();
    String dest = pendingmsg.substring(4);              
    if (protocol.author.equals(dest)) {
        sendMsg(msg);
        pendingmsgs.remove(pendingmsg);
    }
}

これは私が得るものです:

Exception in thread "Thread-3" java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(Unknown Source)
at java.util.AbstractList$Itr.next(Unknown Source)
at ChatServer$ClientConnection.run(ChatServer.java:383)
at java.lang.Thread.run(Unknown Source)

どうすれば修正できますか?イテレータを使用しているからですか?

4

4 に答える 4

3

これの代わりに

pendingmsgs.remove(pendingmsg);

使用する

itpendingmsgs.remove();

IteratorofArrayListfail fastであるため、基になる ifArrayListを使用して反復している間、それ自体が提供する以外の方法で変更され、スローされ、救済されます。IteratorArrayListaddremoveIteratorConcurrentModificationException

現在の実装では、特定の条件でリストをループしているときremoveに、基になるを呼び出してリストを変更しArrayList、代わりにremoveのメソッドを呼び出しますIterator

Java ドキュメントから:

このクラスの iterator および listIterator メソッドによって返される反復子はフェイルファストです。反復子の作成後にリストが構造的に変更された場合、反復子自体の remove または add メソッド以外の方法で、反復子は ConcurrentModificationException をスローします。したがって、同時変更に直面した場合、反復子は、将来の不確定な時点で恣意的で非決定論的な動作を危険にさらすのではなく、迅速かつ明確に失敗します。

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

于 2012-05-21T18:54:00.077 に答える
1

iteratorインスタンス自体を除いて、反復中にリストを変更することはできません。に電話する必要がありますitpendingmsgs.remove()

于 2012-05-21T18:54:15.990 に答える
1

ドキュメンテーションArrayList api に基づくこのクラスの iterator および listIterator メソッドによって返される反復子は、フェイルファストです。反復子の作成後にリストが構造的に変更された場合、反復子自体の remove または add メソッド以外の方法で、反復子がConcurrentModificationException をスローします。

コレクションを反復している間は、コレクションから削除しないでください。代わりに、反復子の remove メソッドを使用する必要があります。

for(Iterator<String> itpendingmsgs = pendingmsgs.iterator(); itpendingmsgs.hasNext();) {
String pendingmsg = itpendingmsgs.next();
String dest = pendingmsg.substring(4);              
if (protocol.author.equals(dest)) {
    sendMsg(msg);
    itpendingmsgs.remove();
}

}

于 2012-05-21T19:02:24.360 に答える
1

それ以外の

pendingmsgs.remove(pendingmsg);

使用する

itpendingmsgs.remove();

見る:

反復の進行中に、このメソッドを呼び出す以外の方法で基になるコレクションが変更された場合、反復子の動作は規定されていません。

ソース: Java API

于 2012-05-21T18:55:55.660 に答える