2016-02-01 2 views
0

У меня есть этот кусок кода:ява intstream данных Опуская параллельный цикл

ArrayList<ArrayList<Double> results = new ArrayList<ArrayList<Double>(); 
IntStream.range(0, 100).parallel().forEach(x ->{ 
    for (int y = 0; y <100;y++){ 
     for (int z = 0; z <100;z++){ 
      for (int q = 0; q <100;q++){ 
       results.add(someMethodThatReturnsArrayListDouble); 
      } 
     } 
    } 
}); 

System.out.println(results.size()); 

После выполнения этого кода, я получаю всегда разные results.size(), всегда несколько короткий. Любая идея, почему это и как ее исправить?

+2

'ArrayList' не является потокобезопасным. – khelwood

+0

Вы должны прочитать раздел о побочных эффектах в [документации] (https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#Statelessness) ... – assylias

ответ

1

использование Vector

это потокобезопасный реализация списка.

1

ArrayList не является потоковым. Если вы попытаетесь добавить к нему элементы в разных потоках (это то, что делает параллелированный поток), он, вероятно, сломается.

От docs:

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

Самое простое исправить в этом случае было бы удаление вызова на parallel().

2

Результат не синхронизирован. Существует несколько способов решения вашей проблемы, лучше всего, чтобы java-поток api обрабатывал объединение списков.

List<List<Double>> results = IntStream.range(0, 100).parallel().flatmap(x ->{ 
     List<Double>> results = new ArrayList<Double>(); 
     for (int y = 0; y <100;y++){ 
      for (int z = 0; z <100;z++){ 
       for (int q = 0; q <100;q++){ 

        results.add(someMethodThatReturnsArrayListDouble); 

       } 
      } 
     } 
     return results.stream(); 
    }).collect(Collectors.toList()); 

Это собирает списки в методе, и возвращает их в поток, чтобы быть объединены в конце метода с использованием collectors.toList(), что является поточно.

+0

спасибо, я обязательно попробую это. Прежде чем перейти к учебному доктору и тому подобное, не могли бы вы переписать код, если бы я хотел изменить x с помощью y? что цикл для x будет классическим для, а цикл Y будет IntStream, я запутался, куда положить коллекционер, тогда – user3338991

Смежные вопросы