Итератор в потоке на CopyOnWriteArrayList не работает

Я делаю некоторые упражнения для экзамена 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();
}

вывод (иногда - так как есть темы) первая прочитанная нить печатает некоторые числа, вторая прочитанная нить не будет печатать никакие числа

использование пользовательского класса потока - работает как положено

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();
}

вывод - работает как положено первая прочитанная нить печатает некоторые числа, вторая читающая нить печатает все числа

В настоящее время я работаю на машине с Win10, с JDK 1.7.0_25 и Eclipse Mars Release 4.5.0

1 ответ

Поскольку @user2357112 опубликовал, нет ничего плохого в коде. Кажется, проблема связана с Eclipse!

При запуске кода вопроса в Eclipse Mars / JRE 1.7.0_25 он не будет печатать числа от 0 до 9999. Вместо этого он сразу же завершит работу, как если бы не было нового итератора.

Я скомпилировал код из командной строки и запустил его, используя java.exe а также javaw.exe, Оба показали правильный вывод.

команда Java

java -classpath "c:\Chapter14\ConcurrentCollections\bin" concurrentCollections.TestClass

результат

Вывод командной строки - соответствующие части

команда javaw

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

результат

содержимое тестового файла - первые числа ххх - содержит все числа

Прямо сейчас я могу сказать (наверняка), нет ничего плохого ни с моим кодом, ни с JVM!

РЕДАКТИРОВАТЬ

Я перенаправил вывод в файл, изменив настройки запуска. Перезапустил приложение в затмении. Output.txt содержит все числа - но в моем окне консоли в Eclipse (распределить консоль) числа не появятся...

Запустите настройки Eclipse

Другие вопросы по тегам