Это не имеет ничего общего с JIT-компилятором, но с реализацией Stream API.Он разделит рабочую нагрузку на куски, которые последовательно обрабатываются рабочими потоками.Общая стратегия состоит в том, чтобы иметь больше заданий, чем рабочих потоков, для включения кражи работы, см., Например, ForkJoinTask.getSurplusQueuedTaskCount()
, который можно использовать для реализации такой адаптивной стратегии.
Следующий кодможет использоваться для определения, сколько элементов было обработано последовательно, когда источником является ArrayList
:
List<Object> list = new ArrayList<>(Collections.nCopies(10_000, ""));
System.out.println(System.getProperty("java.version"));
System.out.println(Runtime.getRuntime().availableProcessors());
System.out.println( list.parallelStream()
.collect(
() -> new ArrayList<>(Collections.singleton(0)),
(l,x) -> l.replaceAll(i -> i + 1),
List::addAll) );
На моем текущем тестовом компьютере он печатает:
1.8.0_60
4
[625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625, 625]
Так что естьбольше кусков, чем ядер, чтобы позволить краже работы.Однако, как только началась последовательная обработка фрагмента, он не может быть разделен далее, поэтому эта реализация имеет ограничения, когда время выполнения для каждого элемента существенно различается.Это всегда компромисс.