Ответ
Нет, Parallel Stream по умолчанию использует общий ForkJoinPool.
1. Общий пул (ForkJoinPool.commonPool()):
- Размер:
Runtime.getRuntime().availableProcessors() - 1 - Общий для всех Parallel Stream в JVM
- Может привести к contention при одновременном выполнении многих параллельных операций
2. Пример использования общего пула:
List<Integer> numbers = IntStream.range(0, 1_000_000).boxed().collect(Collectors.toList());
// Использует commonPool
long count = numbers.parallelStream()
.filter(n -> n % 2 == 0)
.count();
System.out.println("Parallelism: " + ForkJoinPool.commonPool().getParallelism());
3. Использование кастомного пула:
ForkJoinPool customPool = new ForkJoinPool(4); // 4 потока
try {
List<String> result = customPool.submit(() ->
largeList.parallelStream()
.map(item -> processItem(item)) // CPU-intensive операция
.filter(Objects::nonNull)
.collect(Collectors.toList())
).get(); // Блокирующий вызов
} finally {
customPool.shutdown();
}
4. Когда использовать кастомный пул:
- Длительные CPU-bound задачи, чтобы не блокировать commonPool.
- Изоляция критичных по времени операций.
- Контроль приоритетов разных типов задач.
5. Best Practices для Parallel Stream:
// ПЛОХО: Мелкие задачи - накладные расходы
list.parallelStream().map(x -> x + 1).collect(Collectors.toList());
// ХОРОШО: Тяжелые вычисления
list.parallelStream()
.map(item -> {
// Тяжелая операция (> 1ms)
return expensiveCalculation(item);
})
.collect(Collectors.toList());
// ПЛОХО: Блокирующие операции (I/O)
urls.parallelStream()
.map(url -> download(url)) // Блокирующий вызов
.collect(Collectors.toList());
// ХОРОШО: Использование CompletableFuture для I/O
List<CompletableFuture<String>> futures = urls.stream()
.map(url -> CompletableFuture.supplyAsync(() -> download(url), ioExecutor))
.collect(Collectors.toList());
6. Альтернативы для I/O операций:
CompletableFutureс отдельнымExecutorService- Реактивные стримы (Project Reactor, RxJava)
- Виртуальные потоки (Java 21+)