Этот вопрос связан не с известным и документированным фактом, что HashMap
не является потокобезопасным, а касается конкретных режимов отказа в коде HotSpot и JDK. Я удивлен тем, насколько с легкостью этот код выходит из строя с NPE:
public static void main(String[] args) {
Map<Integer, Integer> m = new HashMap<>(0, 0.75f);
IntStream.range(0, 5).parallel().peek(i -> m.put(i, i)).map(m::get).count();
}
Нет никакой тайны относительно того, откуда приходит NPE: на шаге .map(m::get)
при попытке распаковать a null
. Он не работает примерно в 4 из 5 запусков.
На моей машине Runtime#availableProcessors()
сообщает 8, поэтому, предположительно, диапазон длины 5 разбит на 5 подзадач, каждый из которых имеет только один член. Я также предполагаю, что мой код работает в интерпретируемом режиме. Это может быть вызов JIT-скомпилированных методов HashMap
или Stream
, но верхний уровень интерпретируется, поэтому исключает любые изменения, в которых состояние HashMap
загружается в локальную память потока (регистры/стек), тем самым задерживая наблюдение обновлений другого потока. Если некоторые из пяти операций put
не выполняются буквально в одно и то же время на разных ядрах, я не ожидаю, что он разрушит внутреннюю структуру HashMap
. Сроки отдельных задач должны быть чрезвычайно точными, учитывая небольшой объем работы.
Точно ли точное время (commonPool
потоки должны быть неактивными), или есть другой маршрут, который может привести к сбою в Oracle/OpenJDK HotSpot? Моя текущая версия
java version "1.8.0_72"
Java(TM) SE Runtime Environment (build 1.8.0_72-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.72-b15, mixed mode)
ОБНОВЛЕНИЕ: я считаю, что даже создание только двух вставк имеет такую же высокую частоту отказа:
IntStream.range(0, 2).parallel().peek(i -> m.put(i, i)).map(m::get).count();