Получение исключения при выполнении параллельного Stream Java 8 - PullRequest
1 голос
/ 14 октября 2019

Я пишу функцию, которая вычисляет сумму квадратов цифры для данного числа. Я вызываю эту функцию для номера от 1 до 1000 параллельно. Но я получаю исключение через некоторое время.

public static void main(String[] args) throws Exception {
    IntStream stream = IntStream.rangeClosed(1, 1000);
    Map < Integer, Integer > numbers = new TreeMap < > ();
    stream.parallel().forEach(i - > {
        int result = digitSquareSum(i);
        numbers.put(i, result);
    });
    Files.write(Paths.get("result.csv"), () - > numbers.entrySet().stream()
        . < CharSequence > map(e - > e.getKey() + "," + e.getValue())
        .iterator());
}

private static int digitSquareSum(int i) {
    int result = 0;
    int temp = 0;
    while (i != 0) {
        temp = i % 10;
        result = result + temp * temp;
        i = i / 10;
    }
    return result;
}

Я получаю следующее исключение

Exception in thread "main" java.lang.NullPointerException
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:488)
    at java.base/java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:590)
    at java.base/java.util.concurrent.ForkJoinTask.reportException(ForkJoinTask.java:668)
    at java.base/java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:726)
    at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateParallel(ForEachOps.java:160)
    at java.base/java.util.stream.ForEachOps$ForEachOp$OfInt.evaluateParallel(ForEachOps.java:189)
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)
    at java.base/java.util.stream.IntPipeline.forEach(IntPipeline.java:417)
    at java.base/java.util.stream.IntPipeline$Head.forEach(IntPipeline.java:574)

Моя цель - написать эффективный метод, который вычисляет сумму квадратов цифры числа и записывает ее в файл CSV по возрастаниюпорядок заказа.

1 Ответ

1 голос
/ 15 октября 2019

Как уже упоминалось в комментариях, вы получаете это исключение, потому что TreeMap не является потокобезопасным. From javadoc :

Обратите внимание, что эта реализация не синхронизирована. Если несколько потоков обращаются к карте одновременно, и хотя бы один из потоков изменяет картуструктурно он должен быть внешне синхронизирован. (Структурная модификация - это любая операция, которая добавляет или удаляет одно или несколько сопоставлений; простое изменение значения, связанного с существующим ключом, не является структурной модификацией.)

Я полагаю, вы используете TreeMap длясохранить порядок ваших начальных номеров. Но это не обязательно (а также вводит побочные эффекты ): вы можете использовать Collectors.toList () , который собирает все входные элементы в список в порядке встречи .

Это также позволит вам избежать создания второго потока для записи этих чисел в файл:

List<String> lines = IntStream.rangeClosed(1, 1000)
            .parallel()
            .mapToObj(i -> i + " -> " + digitSquareSum(i))
            .collect(Collectors.toList());
Files.write(Paths.get("result.csv", lines); // the lines will come in the right order
...