1

OCP 試験の演習を行っています。現時点では、複数のスレッドを使用しているときにCopyOnWriteArrayList内容出力しようとしました。ドキュメントによると、 CopyOnWriteArrayList のイテレータは

イテレータが作成された時点で存在するリスト内の番号を出力します

そのため、あるスレッドが CopyOnWriteArrayList に書き込みを開始し、のスレッドが CopyOnWriteArrayListから読み取りを開始すると、(時々) いくつかの項目が出力されると予想されます。書き込みスレッドが終了したに CopyOnWriteArrayList をトラバースすると、新しいイテレータがすべてのアイテムを出力することが期待されます。

残念ながら、Runnable インターフェイスの匿名実装を使用している場合、これは機能しません。ただし、CopyOnWriteArrayList への参照を渡すカスタム スレッド クラスを使用する場合は機能します。

今のところ、なぜこれが起こるのかわかりません。この効果が発生するかどうかはわかりませんfinal CopyOnWriteArrayList<Integer> intList = new CopyOnWriteArrayList<>();が、そうである場合は、その理由がまったくわかりません。

このトピックに関するご意見をお待ちしております。

Runnable の匿名実装の使用 - 期待どおりに動作しない

static void copyOnWriteCollections() {
    System.out.println("copyOnWriteCollections".toUpperCase());

    final CopyOnWriteArrayList<Integer> intList = new CopyOnWriteArrayList<>();

    Thread tADD = new Thread(new Runnable() {
        public void run() {
            for (int i = 0; i < 10000; i++) {
                intList.add(i);
            }
        }
    });
    tADD.start();

    /// will print the numbers in the list which are present
    /// at the moment the iterator is created
    Thread tREAD = new Thread(new Runnable() {
        public void run() {
            for (Integer i : intList) {
                System.out.print(i);
                System.out.print(" ");
            }
        }
    });     
    tREAD.start();

    try {
        tADD.join();
        tREAD.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    // will print out all numbers - as iterator is created when all
    // modifications
    // to intList have finished
    System.out.println();
    new Thread(new Runnable() {
        public void run() {
            System.out.println("new");
            System.out.println("\tsize of intList: " + intList.size());

            Iterator<Integer> it = intList.iterator();

            while (it.hasNext()) {
                int i = it.next();
                System.out.print(i);
                System.out.print(" ");
            }

            System.out.println("end");
        }
    }).start();
}

出力 (時々 - スレッドがあるため) 最初の読み取りスレッドはいくつかの数値を出力しますが、2 番目の読み取りスレッドは数値を出力しません!

カスタム スレッド クラスの使用 - 期待どおりに動作します

class CopyOnWriteThread extends Thread {

    Iterator<Integer> it = null;
    boolean read = false;
    CopyOnWriteArrayList<Integer> intList = null;

    public CopyOnWriteThread(CopyOnWriteArrayList<Integer> intList, boolean read) {
        this.intList = intList;
        this.read = read;
    }

    public void run() {
        if (read) {
            it = intList.iterator();

            System.out.println("START read (" + Thread.currentThread().getName() + ")");
            System.out.print("\t");
            while (it.hasNext()) {
                System.out.print(it.next());
                System.out.print(" ");
            }
            System.out.println();
            System.out.println("END read (" + Thread.currentThread().getName() + ")");
        } else {
            System.out.println("START write (" + Thread.currentThread().getName() + ")");
            for (int i = 0; i < 10000; i++) {
                intList.add(i);
            }
            System.out.println("END write (" + Thread.currentThread().getName() + ")");
        }
    }
}

static void copyOnWriteCollections_CustomThread() {
    CopyOnWriteArrayList<Integer> intList = new CopyOnWriteArrayList<>();

    CopyOnWriteThread tWRITE = new CopyOnWriteThread(intList, false);
    CopyOnWriteThread tREAD = new CopyOnWriteThread(intList, true);
    tWRITE.start();
    tREAD.start();

    try {
        tWRITE.join();
        tREAD.join();
    } catch (InterruptedException e) {
    }

    CopyOnWriteThread tREAD2 = new CopyOnWriteThread(intList, true);
    tREAD2.start();
}

出力 - 期待どおりに動作します 最初の読み取りスレッドはいくつかの数値を出力し、2 番目の読み取りスレッドはすべての数値を出力します

現在、JDK 1.7.0_25 および Eclipse Mars Release 4.5.0 を使用して、Win10 マシンで作業しています。

4

1 に答える 1

0

@ user2357112 が投稿したように、コードに問題はありません。問題はEclipseに関連しているようです!

Eclipse Mars / JRE 1.7.0_25 で質問コードを実行すると、0 から 9999 までの数字が出力されません。代わりに、新しい iterator がないかのようにすぐに終了します。

コマンドラインからコードをコンパイルし、 and を使用して開始しましjava.exejavaw.exe。どちらも正しい出力を示しました。

java コマンド

java -classpath "c:\Chapter14\ConcurrentCollections\bin" 並行コレクション.TestClass

結果

コマンドライン出力 - 関連部分

javaw コマンド

javaw -classpath "c:\Chapter14\ConcurrentCollections\bin" concurrentCollections.TestClass > "c:\test.txt"

結果

テスト ファイルの内容 - 最初の xxx 番号 - すべての番号を含む

現時点では、(確かに) 私のコードにも JVM にも問題はないと言えます。

編集

Run Configurationsを変更して、出力をファイルにリダイレクトしました。Eclipseでアプリケーションを再起動しました。Output.txtすべての数字が含まれています-しかし、Eclipse内の私のコンソールウィンドウ(コンソールの割り当て)には数字が表示されません...

実行構成 Eclipse

于 2016-03-23T11:22:12.183 に答える