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()"

Answer from Lukáš Křečan on Stack Overflow
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.

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.

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
Which way it is thread-safe in Java Stream?
Please ensure that: Your code is properly formatted as code block - see the sidebar (About on mobile) for instructions You include any and all error messages in full You ask clear questions You demonstrate effort in solving your question/problem - plain posting your assignments is forbidden (and such posts will be removed) as is asking for or giving solutions. Trying to solve problems on your own is a very important skill. Also, see Learn to help yourself in the sidebar If any of the above points is not met, your post can and will be removed without further warning. Code is to be formatted as code block (old reddit: empty line before the code, each code line indented by 4 spaces, new reddit: https://imgur.com/a/fgoFFis ) or linked via an external code hoster, like pastebin.com, github gist, github, bitbucket, gitlab, etc. Please, do not use triple backticks (```) as they will only render properly on new reddit, not on old reddit. Code blocks look like this: public class HelloWorld { public static void main(String[] args) { System.out.println("Hello World!"); } } You do not need to repost unless your post has been removed by a moderator. Just use the edit function of reddit to make sure your post complies with the above. If your post has remained in violation of these rules for a prolonged period of time (at least an hour), a moderator may remove it at their discretion. In this case, they will comment with an explanation on why it has been removed, and you will be required to resubmit the entire post following the proper procedures. To potential helpers Please, do not help if any of the above points are not met, rather report the post. We are trying to improve the quality of posts here. In helping people who can't be bothered to comply with the above points, you are doing the community a disservice. I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns. More on reddit.com
🌐 r/javahelp
8
2
August 22, 2021
🌐
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 - It typically creates as many worker threads as there are processors available to the Java Virtual Machine (JVM). This means that the number of threads created for a parallel stream is usually equal to the number of available processor cores.
🌐
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.
🌐
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 - Then we created a custom fork-join pool with a size of five. Finally, we executed the parallelStream statement inside of the submit block. This control threads number in Java parallel stream and enforces the stream to process five records max at the same time.
Find elsewhere
🌐
DEV Community
dev.to › hugaomarques › why-your-parallelstream-might-not-be-parallel-at-all-g7e
Why Your `.parallelStream()` Might Not Be Parallel at All - DEV Community
April 6, 2025 - When we use .parallelStream() in Java, we expect parallelism to magically kick in — blazing fast execution across multiple threads. But sometimes, even with .parallelStream(), everything still runs in a single thread. No speedup. No parallelism. Just disappointment. 😤 ... List<String> users = List.of("alice", "bob"); List<String> products = IntStream.range(0, 10_000) .mapToObj(i -> "product-" + i) .toList(); List<String> result = users.stream() .flatMap(user -> products.parallelStream() .map(product -> { System.out.println("Sequential map: " + user + " - " + product + " on " + Thread.currentThread().getName()); return user + " → " + product; }) ) .toList();
🌐
DEV Community
dev.to › igalhaddad › java-8-parallel-stream-with-threadpool-32kd
Java 8 Parallel Stream with ThreadPool - DEV Community
February 10, 2020 - That method uses ThreadExecutor utility to execute a parallel stream on a separate dedicated thread pool consisting of number of threads as provided, where each thread is named "FibonacciTask" concatenated with a serial number, e.g., ...
🌐
Medium
medium.com › @daniel.las › performance-of-parallel-java-streams-68988191d9f8
Performance of parallel Java Streams | by Daniel Las | Medium
April 21, 2024 - The difference is that the tested code was executed in 2, 4, 6, 8, 10,12, 14 and 16 threads at the same time on 4 CPU cores virtual machine. Every benchmark was executed against stream of size 1000 and 100 000 to check if the size matters.
🌐
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.
🌐
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 - By adjusting maxConcurrency, we control the number of concurrent tasks based on the system's capacity. With this new feature, processing large volumes of images is much easier and more efficient. The Java ecosystem is constantly evolving, and the inability to directly use virtual threads with parallel streams is likely a temporary limitation.
🌐
Oracle
docs.oracle.com › javase › tutorial › collections › streams › parallelism.html
Parallelism (The Java™ Tutorials > Collections > Aggregate Operations)
Operations like forEach and peek ... with care; if you use one of these operations with a parallel stream, then the Java runtime may invoke the lambda expression that you specified as its parameter concurrently from multiple threads....
🌐
Glassthought
glassthought.com › notes › lc2wo9z3twpqypqncncbgzd
Parallel Streams with Custom Thread Pool - GlassThought.com
December 21, 2023 - import java.util.List; import java.util.concurrent.ForkJoinPool; import java.util.stream.Collectors; public class ParallelStreamExample { public static void main(String[] args) { List<Integer> data = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); int numberOfThreads = 4; // Specify the number of threads ...
🌐
Coderanch
coderanch.com › t › 657360 › java › Specific-Number-Parallel-Streams
Specific Number of Parallel Streams (Features new in Java 8 forum at Coderanch)
Welcome to the Ranch Does a parallel stream allow you to specify the number of threads/streams used at all? Let's look at the parallel method. It doesn't take any arguments and doesn't appear to be overloaded.
🌐
Java Code Geeks
javacodegeeks.com › home › core java
Java 8 Parallel Streams - Custom Thread Pools Examples - Java Code Geeks
April 28, 2021 - Look at the below program, that runs with 5 threads using ForkJoinPool and inside creating a new parallel stream to find the sum of all numbers for the given range.
🌐
Xperti
xperti.io › home › when to use the parallel stream in java
When To Use The Parallel Stream In Java
May 2, 2022 - 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.
🌐
Stack Abuse
stackabuse.com › java-8-streams-guide-to-parallel-streaming-with-parallel
Java 8 Streams: Definitive Guide to Parallel Streaming with parallel()
October 24, 2023 - The parallel() call triggers the fork-join mechanism on the stream of numbers. It splits the stream to run in four threads.
🌐
DZone
dzone.com › coding › java › think twice before using java 8 parallel streams
Think Twice Before Using Java 8 Parallel Streams
August 13, 2019 - Here, we do not deal with a CPU-intensive operation, but we can take advantage of parallelization too. It's a good idea to execute multiple network request in parallel. Again, a nice task for parallel streams, do you agree? If you do, please look at the previous example again. There is a big error. Do you see it? The problem is that all parallel streams use common fork-join thread pool, and if you submit a long-running task, you effectively block all threads in the pool.