Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parallel Stream with Virtual Threads: Java VirtualThread equivalent for ForkJoinWorkerThread

I'm experimenting with Java virtual threads and wonder if it's possible to run parallel Streams with virtual threads. By default, parallel streams are run on the common ForkJoinPool, but one could use a custom thread pool by calling a Stream's terminal operation on the worker thread of another ForkJoinPool. But as of JDK 20, ForkJoinPool can only manage threads of ForkJoinWorkerThread instances.

Is there a VirtualThread equivalent for ForkJoinWorkerThread? Or is there an alternative way to run tasks in a work-stealing manner using virtual threads?

Practical use case: This is useful when the stream source blocks while waiting for data, is pageable, and allows concurrent access, and when the subsequent intermediate and terminal stream operations are CPU-bound.

like image 706
Warren Nocos Avatar asked Aug 17 '26 16:08

Warren Nocos


1 Answers

Virtual threads (project Loom) are designed for high-throughput I/O-bound concurrency (e.g., handling thousands of network requests), while parallel streams rely on work-stealing with CPU-bound parallelism via ForkJoinPool. These are different concurrency models.

Virtual threads cannot replace ForkJoinWorkerThread. The JVM's work-stealing scheduler requires tight control over threads that virtual threads intentionally avoid. As of Java 21, parallel streams still cannot use virtual threads. The ForkJoinPool is hardcoded to use platform threads.

What to do:

  1. For CPU-bound parallel work (e.g., math calculations):
    Stick with the default ForkJoinPool.

    List<Integer> results = data.parallelStream()
        .map(this::cpuIntensiveOperation)
        .toList();
    
  2. For I/O-bound concurrency (e.g., HTTP calls):
    Ditch parallel streams entirely. Use virtual threads directly with structured concurrency:

    try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
        List<CompletableFuture<String>> futures = urls.stream()
            .map(url -> CompletableFuture.supplyAsync(() -> fetch(url), executor))
            .toList();
    
        List<String> results = futures.stream()
            .map(CompletableFuture::join)
            .toList();
    }
    
like image 136
eyesoflight Avatar answered Aug 19 '26 09:08

eyesoflight



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!