Итератор в потоке на 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 (распределить консоль) числа не появятся...