Java 17’s parallelStream() causes critical performance issues with code that runs fine in Java 16. Why?

We all know or be told that creating a new thread is a heavy operation. But it seems okay to me after ran a few tests. For example: Here is the memory usage by run below simple test with 10_000 thread. It took about 2 or 3 seconds on my laptop and jvm usage is about 1.5 G.

final int threadNum = 10_000;

final Callable<String> task = () -> {
    String bigString = UUID.randomUUID().toString().repeat(1000);
    assertTrue(bigString.chars().sum() > 0);


    return bigString;

final ExecutorService executorService = Executors.newFixedThreadPool(threadNum);
final List<Future<String>> futures = new ArrayList<>(threadNum);

for (int i = 0; i < threadNum; i++) {

long ret =;
assertEquals(UUID.randomUUID().toString().length() * threadNum * 1000, ret);

enter image description here

I think it’s a rare chance that 10_000 will be created/used in most of applications. If I changed the thread number to 1000. Again it took 2 or 3 seconds and memory usage is about: 300 MB.
enter image description here

Is it possible or a good idea to use stream api to run blocking I/O call in parallel? I think so. Here is a sample with my tool: abacus-common

// Run above task by Stream.
ret = IntStreamEx.range(0, threadNum)
        .mapToObj(it ->

// Or other  task
        .parallel(64) // Specify the concurrent thread number. It could be from 1 up to thousands.

Or use Virtual Threads introduced in Java 19+

try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {

I know this is not a direct answer to the question. But it may resolve the original problem which brought up this question.

Leave a Comment