Update
Originally this answer was an elaborate explanation claiming that the ForkJoinPool
applies back-pressure and doesn't even reach the prescribed parallelism level, because there are always idle workers available to process the stream.
That's incorrect.
The actual answer is provided in the original question to which this was marked as duplicate - using a custom ForkJoinPool
for stream processing is not officially supported, and when using forEach
, the default pool parallelism is used to determine the stream spliterator behavior.
Here's an example how when tasks are manually submitted to a custom ForkJoinPool
, the pool's active thread count easily reaches its parallelism level:
for (int i = 0; i < 1_000_000; ++i) {
forkJoinPool.submit(() -> {
try {
Thread.sleep(1);
thNames.add(Thread.currentThread().getName());
System.out.println("Size: " + thNames.size() + " activeCount: " + forkJoinPool.getActiveThreadCount() + " parallelism: " + forkJoinPool.getParallelism());
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
Thanks to Stuart Marks for pointing this out and to Sotirios Delimanolis for arguing that my original answer is wrong :)