The Oracle's implementation[1] of parallel stream uses the current thread and in addition to that, if needed, also the threads that compose the default fork join pool ForkJoinPool.commonPool(), which has a default size equal to one less than the number of cores of your CPU.

That default size of the common pool can be changed with this property:

-Djava.util.concurrent.ForkJoinPool.common.parallelism=8

Alternatively, you can use your own pool:

ForkJoinPool myPool = new ForkJoinPool(8);
myPool.submit(() ->
    list.parallelStream().forEach(/* Do Something */);
).get();

Regarding the order, jobs will be executed as soon as a thread is available, in no specific order.

As correctly pointed out by @Holger this is an implementation specific detail (with just one vague reference at the bottom of a document), both approaches will work on Oracle's JVM but are definitely not guaranteed to work on JVMs from other vendors, the property could not exist in a non-Oracle implementation and Streams could not even use a ForkJoinPool internally rendering the alternative based on the behavior of ForkJoinTask.fork completely useless (see here for details on this).

Answer from uraimo on Stack Overflow
Top answer
1 of 2
144

The Oracle's implementation[1] of parallel stream uses the current thread and in addition to that, if needed, also the threads that compose the default fork join pool ForkJoinPool.commonPool(), which has a default size equal to one less than the number of cores of your CPU.

That default size of the common pool can be changed with this property:

-Djava.util.concurrent.ForkJoinPool.common.parallelism=8

Alternatively, you can use your own pool:

ForkJoinPool myPool = new ForkJoinPool(8);
myPool.submit(() ->
    list.parallelStream().forEach(/* Do Something */);
).get();

Regarding the order, jobs will be executed as soon as a thread is available, in no specific order.

As correctly pointed out by @Holger this is an implementation specific detail (with just one vague reference at the bottom of a document), both approaches will work on Oracle's JVM but are definitely not guaranteed to work on JVMs from other vendors, the property could not exist in a non-Oracle implementation and Streams could not even use a ForkJoinPool internally rendering the alternative based on the behavior of ForkJoinTask.fork completely useless (see here for details on this).

2 of 2
5

While @uraimo is correct, the answer depends on exactly what "Do Something" does. The parallel.streams API uses the CountedCompleter Class which has some interesting problems. Since the F/J framework does not use a separate object to hold results, long chains may result in an OOME. Also those long chains can sometimes cause a Stack Overflow. The answer to those problems is the use of the Paraquential technique as I pointed out in this article.

The other problem is excessive thread creation when using nested parallel forEach.

Top answer
1 of 16
520

There actually is a trick how to execute a parallel operation in a specific fork-join pool. If you execute it as a task in a fork-join pool, it stays there and does not use the common one.

final int parallelism = 4;
ForkJoinPool forkJoinPool = null;
try {
    forkJoinPool = new ForkJoinPool(parallelism);
    final List<Integer> primes = forkJoinPool.submit(() ->
        // Parallel task here, for example
        IntStream.range(1, 1_000_000).parallel()
                .filter(PrimesPrint::isPrime)
                .boxed().collect(Collectors.toList())
    ).get();
    System.out.println(primes);
} catch (InterruptedException | ExecutionException e) {
    throw new RuntimeException(e);
} finally {
    if (forkJoinPool != null) {
        forkJoinPool.shutdown();
    }
}

The trick is based on ForkJoinTask.fork which specifies: "Arranges to asynchronously execute this task in the pool the current task is running in, if applicable, or using the ForkJoinPool.commonPool() if not inForkJoinPool()"

2 of 16
251

The parallel streams use the default ForkJoinPool.commonPool which by default has one less threads as you have processors, as returned by Runtime.getRuntime().availableProcessors() (This means that parallel streams leave one processor for the calling thread).

For applications that require separate or custom pools, a ForkJoinPool may be constructed with a given target parallelism level; by default, equal to the number of available processors.

This also means if you have nested parallel streams or multiple parallel streams started concurrently, they will all share the same pool. Advantage: you will never use more than the default (number of available processors). Disadvantage: you may not get "all the processors" assigned to each parallel stream you initiate (if you happen to have more than one). (Apparently you can use a ManagedBlocker to circumvent that.)

To change the way parallel streams are executed, you can either

  • submit the parallel stream execution to your own ForkJoinPool: yourFJP.submit(() -> stream.parallel().forEach(soSomething)).get(); or
  • you can change the size of the common pool using system properties: System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "20") for a target parallelism of 20 threads.

Example of the latter on my machine which has 8 processors. If I run the following program:

long start = System.currentTimeMillis();
IntStream s = IntStream.range(0, 20);
//System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "20");
s.parallel().forEach(i -> {
    try { Thread.sleep(100); } catch (Exception ignore) {}
    System.out.print((System.currentTimeMillis() - start) + " ");
});

The output is:

215 216 216 216 216 216 216 216 315 316 316 316 316 316 316 316 415 416 416 416

So you can see that the parallel stream processes 8 items at a time, i.e. it uses 8 threads. However, if I uncomment the commented line, the output is:

215 215 215 215 215 216 216 216 216 216 216 216 216 216 216 216 216 216 216 216

This time, the parallel stream has used 20 threads and all 20 elements in the stream have been processed concurrently.

Discussions

Given a large number of tasks, are threads or parallel streams more performant?
Parallel streams are implemented using internal threads. So...not sure if it would make any difference regarding performance. More on reddit.com
🌐 r/java
15
14
July 27, 2015
Is it possible to use virtual threads with parallel streams?
Parallel streams don't have to use the global fork join pool. If you use them in the context of your own fork join pool, that's the one they will use More on reddit.com
🌐 r/java
20
37
March 22, 2023
A surprising pain point regarding Parallel Java Streams (featuring mailing list discussion with Viktor Klang).
I did want to follow up about one point Viktor made later on in the conversation. https://mail.openjdk.org/pipermail/core-libs-dev/2024-November/134542.html And here is the quote. In a potential future where all intermediate operations are Gatherer-based, and all terminal operations are Collector-based, it would just work as expected. But with that said, I'm not sure it is practically achievable because some operations might not have the same performance-characteristics as before. Me personally, I would GLADLY accept a flag on stream (similar to parallel() or unordered()) that would allow me to guarantee that my stream never pre-fetches, even if I take a massive performance hit. If that can be accomplished by making all intermediate operations be implemented by a Gatherer under the hood, that is A-OK with me. The reality is, not all streams are compute bound. Some are IO bound, but are otherwise, a great fit for streams. Having a method that allows us to optimize for that fact is a new type of performance enhancement that I would greatly appreciate, even if it degrades performance in other ways. More on reddit.com
🌐 r/java
94
223
November 20, 2024
Custom Thread Pools In Java Parallel Streams
Wish I read this before starting my current project. I was getting crazy memory leaks before I found out you had to shutdown the thread pools. Good article for beginners in parallel processing More on reddit.com
🌐 r/java
6
36
February 14, 2023
🌐
Baeldung
baeldung.com › home › java › java concurrency › custom thread pools in java parallel streams
Custom Thread Pools in Java Parallel Streams | Baeldung
December 28, 2023 - We used the ForkJoinPool constructor with a parallelism level of 4. Some experimentation is required to determine the optimal value for different environments, but a good rule of thumb is simply choosing the number based on how many cores your CPU has. Next, we processed the content of the parallel Stream, summing them up in the reduce call. This simple example may not demonstrate the full usefulness of using a custom thread pool, but the benefits become obvious in situations where we do not want to tie-up the common thread pool with long-running tasks – such as processing data from a network source – or the common thread pool is being used by other components within the application.
🌐
Medium
medium.com › @sum98kumar › java-interview-questions-9cb306e392d3
Java Interview Questions.. Q. How many thread will open for… | by Suman Kumar | Medium
February 15, 2024 - Ans: In Java, the number of threads that will be opened for a parallel stream depends on the underlying ForkJoinPool that is used to execute parallel streams. Java uses the common ForkJoinPool by default.
🌐
Java2Blog
java2blog.com › home › core java › java 8 › java parallel stream
Java Parallel Stream - Java2Blog
January 26, 2021 - As you can see parallel stream used all 4 CPU cores to perform computation. The parallel stream by default uses ForkJoinPool.commonPool which has one less thread than number of processor.
🌐
Medium
medium.com › geekculture › pitfalls-of-java-parallel-streams-731fe0c1eb5f
Internals Of Java Parallel Streams | by Thameena S | Geek Culture | Medium
July 1, 2021 - So in total 12 tasks can be executed in parallel here (main + ForkJoinPool), using all 12 CPU cores. Parallel stream is configured to use as many threads as the number of cores in the computer or VM on which the program is running.
🌐
DEV Community
dev.to › igalhaddad › java-8-parallel-stream-with-threadpool-32kd
Java 8 Parallel Stream with ThreadPool - DEV Community
February 10, 2020 - The handy ThreadExecutor utility by Igal Haddad offers an elegant solution to this, allowing developers to specify the number of threads, custom thread names, and timeouts, making it ideal for scenarios that require fine-tuned parallel execution. For example, in performance-heavy applications like game cheat engines—think Easy Victory Game Cheats Free—having precise control over thread execution can improve processing speed and debugging clarity.
🌐
Geeky Hacker
geekyhacker.com › home › java › control threads number in java parallel stream
Control threads number in Java parallel stream - Geeky Hacker
March 30, 2024 - It uses the default application fork-join pool. And also the parallelism is not controllable. In this article, we cover how to control threads number in Java parallel stream by using a custom fork-join pool. The idea is to create a custom fork-join pool with a desirable number of threads and execute the parallel stream within it.
Find elsewhere
🌐
Coderanch
coderanch.com › t › 657360 › java › Specific-Number-Parallel-Streams
Specific Number of Parallel Streams (Features new in Java 8 forum at Coderanch)
The following shows this. IF I remove the +1 from the code, it runs to completion. All 16 threads hit the cyclic carrier and then the barrier releases them all at once. However with 17 threads, the last one gets stuck and the program hangs. @Jeanne No, you don't have 2 * Runtime.getRuntime...
🌐
Javacodemonk
javacodemonk.com › java-8-parallel-stream-custom-threadpool-48643a91
Java 8 Parallel Stream custom ThreadPool
August 23, 2020 - There are two approaches to configure ... running parallel stream operation inside ForkJoinPool. Java does not provide any direct mechanism to control the number of threads and ThreadPool used by ......
🌐
Codementor
codementor.io › community › controlling parallelism of java 8 collection streams
Controlling Parallelism of Java 8 Collection Streams | Codementor
January 23, 2017 - When we're using collection streams in parallel of Java, there doesn't seem to be any parameter that takes our own thread pool. Some may wonder how many threads certain operation would be given while others may actually believe that we can leave JVM to it because it would know what to do.
🌐
Medium
medium.com › @michaelbespalov › parallel-stream-pitfalls-and-how-to-avoid-them-91f11808a16c
Parallel stream pitfalls and how to avoid them | by Michael Bespalov | Medium
December 20, 2017 - Since streams were introduced in Java 8, we now have a clean and functional way of processing data. It gets even better when the processing task can be done in parallel with as much as adding .parallel() right after creating the stream. The underlying risk lies in the implementation of parallel streams and the threads they use. By default, the parent thread is used as well as ForkJoin common pool.
🌐
CopyProgramming
copyprogramming.com › howto › how-many-threads-are-spawned-in-parallelstream-in-java-8
Java: Quantifying the Number of Threads Generated by parallelStream in Java 8
April 10, 2023 - Parallel processing - What determines the number of, As far as I had understood ForkJoinPool, that pool creates a fixed number of threads (default: number of cores) and will never create more threads … ... java parallel stream how to wait for threads java parallelstream does not use expected ...
🌐
Daniellas
daniellas.tech › posts › performance-of-parallel-streams.html
Daniel Łaś Tech Blog - Performance of parallel Streams. The truth revealed.
The difference is that tested code ... and 16 threads at the same time on 8 core machine. Every benchmark was executed against stream of size 1000 and 100 000 to check if the size matters. ... The JVM arguments passed in every test were: -Xms2G -Xmx2G -XX:+UseG1GC.
🌐
Baeldung
baeldung.com › home › java › java streams › when to use a parallel stream in java
When to Use a Parallel Stream in Java | Baeldung
November 10, 2025 - In this article, we explored the difference between sequential and parallel streams in Java. We learned that parallel streams make use of the default fork-join pool and its worker threads.
🌐
TheServerSide
theserverside.com › tip › How-to-use-parallel-streams-in-Java-with-virtual-threads
How to use parallel streams in Java with virtual threads | TheServerSide
July 3, 2024 - Parallel streams utilize the fork/join pool which defaults to the number of available cores. This can help improve performance, but it's limited by the pool size and the fact that this is I/O-bound work. Threads can spend significant time blocked, waiting for file operations to complete.
🌐
Xperti
xperti.io › home › when to use the parallel stream in java
When To Use The Parallel Stream In Java
February 4, 2026 - These thread pools are responsible for the execution of small portions of a task assigned to them. The number of threads in the common pool is always equal to the number of processor cores.
🌐
Javaspring
javaspring.net › blog › how-to-set-java-stream-parallel-stream-thread-count
How to Set Java Stream Parallel Stream Thread Count | JavaSpring.net
July 16, 2025 - The Fork - Join framework is designed to split a large task into smaller subtasks and then combine the results of these subtasks. By default, the number of threads used by the Fork - Join pool (which is used by parallel streams) is equal to the number of available processors (Runtime.getRu...