`.sizeを実行しようとすると、` ConcurrentModificationException`を投げるのArrayList() `メソッド

stevendesu:

更新

智異Tousekで指摘された、私のコードでスローされたエラーは、多くのアマチュア(と経験豊富な)Java開発者を誤解しています。名前が意味すると思われるものに反して、ConcurrentModificationExceptionではないマルチスレッドとは何かを持っています。次のコードを考えてみます。

import java.util.List;
import java.util.ArrayList;

class Main {
  public static void main(String[] args) {
    List<String> originalArray = new ArrayList<>();
    originalArray.add("foo");
    originalArray.add("bar");
    List<String> arraySlice = originalArray.subList(0, 1);
    originalArray.remove(0);
    System.out.println(Integer.toString(arraySlice.size()));
  }
}

これがスローされますConcurrentModificationExceptionなしが関与ねじ切りされているにもかかわらず。

誤解を招くような例外名は私の問題は、私はマルチスレッドを処理していたかの結果だったと思うために私を導きました。私はと私の記事のタイトル更新した実際の問題を。

オリジナル(タイトル:あなたは、スレッドでのArrayListの変更が完了していることでJavaを通知する方法は?)

私は次のように大まかなコードを持っています:

class MessageQueue {
    private List<String> messages = new ArrayList<>();
    private List<String> messagesInFlight = new ArrayList<>();

    public void add(String message) {
        messages.add(message);
    }

    public void send() {
        if (messagesInFlight.size() > 0) {
            // Wait for previous request to finish
            return;
        }

        messagesInFlight = messages.subList(0, Math.min(messages.size, 10));
        for( int i = 0; i < messagesInFlight.size(); i++ )
        {
            messages.remove(0);
        }

        sendViaHTTP(messagesInFlight, new Callback() {
            @Override
            public void run() {
                messagesInFlight.clear();
            }
        });
    }
}

これは、分析の目的のために私のコードで利用されています。10秒ごとに私が呼んmessageQueue.send()タイマーから、関心のあるイベントが発生するたびに、私は呼んでmessageQueue.add()このクラスの作品は、*大部分は* -私はメッセージを追加することができ、それらは、HTTPを経由して送信されますと、HTTPリクエストが完了したときにコールバックが実行されます

問題は、タイマーの第二の目盛りに位置しています。私はラインを打つときif (messagesInFlight.size() > 0) {、私は次のエラーを取得します:

java.util.ConcurrentModificationException
        at java.util.ArrayList$SubList.size(ArrayList.java:1057)

私は読むことができないように思える.size()それはまだ他のスレッド(最初のタイマーのコールバック)によって変更されている配列を考えているので、一つのスレッド(第2のタイマーのコールバック)で配列のを。しかし、私は最初のタイマーのスレッドが破壊されたとの私の呼び出しの後にクリーンアップされた期待するsendViaHTTPことは実行するための追加コードがなかったことから、。さらに、HTTPリクエストは、500ミリ秒以内に完了しているので、完全な9.5秒は空に触れる何もせずに渡すmessagesInFlight配列を

「ねえ、私はこの配列は、人々が安全に、今それを読むことができますを修正終わりだ」発言を言うする方法はありますか?それとも、より良い方法は、自分のコードを整理する方法は?

智異Tousek:

あなたが持っている最もまぶしい問題は、あなたが使用していることがありArrayList.subList()ます。それは本当に、何をするか理解していないようですしながら。

このリストの部分のビューを返します...返されたリストは、このリストによって支えられています。

何をして保存していることmessagesInFlightであるビューではなく、コピーあなたが最初からメッセージを削除するときmessages、あなたはあなたの中に持っていた非常にメッセージの削除、実際にしていmessagesInFlightた後、右subList()呼び出しを。だから、後にforループ、完全に異なるメッセージがあるだろう、と最初のn個のメッセージが完全に失われます。


あなたが表示されるエラーを取得している理由として- subList()特にことができます非構造変化サブリストと元のリスト(非構造手段が追加またはそれらを除去しない、要素を置き換える)の両方に、およびドキュメントの例もショーケースをどのように元のリストは、サブリストを修正することによって修正することができます。しかし、元のリストを変更して、サブリストからアクセスすることは許されないとの結果もConcurrentModifcationException、同様にあなたがしているが、イテレータとを反復処理し、リストを変更したときに何が起こるかと。

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=225698&siteId=1