Я пытался воспроизвести (и решить) ConcurrentModificationException
, когда экземпляр HashMap
читается и пишется несколькими Thread
с.
Отказ от ответственности: я знаю, что HashMap
не поддерживает потоки.
В следующем коде:
import java.util.*;
public class MyClass {
public static void main(String args[]) throws Exception {
java.util.Map<String, Integer> oops = new java.util.HashMap<>();
oops.put("1", 1);
oops.put("2", 2);
oops.put("3", 3);
Runnable read = () -> {
System.out.println("Entered read thread");
/*
* ConcurrentModificationException possibly occurs
*
for (int i = 0; i < 100; i++) {
List<Integer> numbers = new ArrayList<>();
numbers.addAll(oops.values());
System.out.println("Size " + numbers.size());
}
*/
for (int i = 0; i < 100; i++) {
List<Integer> numbers = new ArrayList<>();
numbers.addAll(oops.values()
.stream()
.collect(java.util.stream.Collectors.toList()));
System.out.println("Size " + numbers.size());
}
};
Runnable write = () -> {
System.out.println("Entered write thread");
for (int i = 0; i < 100; i++) {
System.out.println("Put " + i);
oops.put(Integer.toString(i), i);
}
};
Thread writeThread = new Thread(write, "write-thread");
Thread readThread = new Thread(read, "read-thread");
readThread.start();
writeThread.start();
readThread.join();
writeThread.join();
}
}
По сути, я делаю два потока: один продолжает помещать элементы в HashMap
, другой выполняет итерации на HashMap.values()
.
В потоке read
, если я использую numbers.addAll(oops.values())
, случайным образом возникает ConcurrentModificationException
.Хотя строки печатаются случайным образом, как и ожидалось.
Но если я переключусь на numbers.addAll(oops.values().stream()..
, я не получу никакой ошибки.Однако я наблюдал странное явление.Все строки в потоке read
печатаются после в строках, напечатанных в нити write
.
Мой вопрос: Collection.stream()
имеет как-то внутреннюю синхронизацию?
ОБНОВЛЕНИЕ :
Используя JDoodle https://www.jdoodle.com/a/IYy,, похоже на JDK9 и JDK10, я получу ConcurrentModificationException
, как и ожидалось.
Спасибо!