2

I am bit confused how Forkjoin internally works vs Thread Pool. Below is the code snippet for the same. Both are having single parallelism. Ideally it should behave same as Thread pool and it should not pick the task unless it finishes.

public class Sample {

public static void main(String[] args) {
    // Use either ThreadPoolExecutor or ForkJoin.
    //ThreadPoolExecutor pool = (ThreadPoolExecutor) Executors.newFixedThreadPool(1);
    ForkJoinPool pool = new ForkJoinPool(1);
    List<Integer> items = new ArrayList<>();
    items.add(1);
    items.add(2);
    // Create 2 task and submit to thread pool. Wait for it to execute all the task.
    pool.submit(() -> {
        try {
            startProcessing(items.get(0));
        } catch (ExecutionException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
    pool.submit(() -> {
        try {
            startProcessing(items.get(1));
        } catch (ExecutionException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });


    try {
        pool.shutdown();
        pool.awaitTermination(10, TimeUnit.SECONDS);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
private static void startProcessing(int itemVal) throws ExecutionException, InterruptedException {
    doProcessing(itemVal).get();
    System.out.println("Ended :" + itemVal);
}

private static CompletableFuture<Integer> doProcessing(int itemVal) throws InterruptedException {
    CompletableFuture<Integer> future = new CompletableFuture<>();
    System.out.println("Started :" + itemVal);
    // I was assuming as this is waiting for child thread to also complete,
    // so this thread will be waiting and hence will be waiting for task 1 untill it finishes.
    // BUT IT GOT CONTEXT SWITCHED AND PICKED THE TASK 2.
    asyncCall(future, itemVal);
    return future;
}

// This is the place where new thread is created.
private static void asyncCall(CompletableFuture<Integer> future, int itemVal) {
    Thread t = new Thread(() -> {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        future.complete(itemVal);
    });
    t.start();
}

}

Below is the output if using Thread pool:

Started :1
Ended :1
Started :2
Ended :2

And below is the output if using Fork Join:

Started :1
Started :2
Ended :1
Ended :2

Why is this difference in behavior for Fork Join compared to thread pool?

Rahul
  • 326
  • 2
  • 10
  • 2
    `Executors.newFixedThreadPool(1)` returns a `ThreadPoolExecutor` configured with it's _core pool size_ and _maximum pool size_ set to 1. It will never have more than one thread at any given time. Whereas `new ForkJoinPool(1)` returns a `ForkJoinPool` with its _parallelism_ set to 1, which is not the same thing; it does not prevent more threads from being created in an attempt to maintain that parallelism level. If you print the thread name along with your started/ended messages, you'll see this. – Slaw Dec 25 '22 at 09:28
  • 1
    See https://stackoverflow.com/questions/67416858/forkjoinpool-size-increasing-dynamically – tgdavies Dec 25 '22 at 09:40
  • See what happens when you *don't* use a thread in asyncCall, and just sleep on the worker thread. Then the ForkJoinPool sees the thread as waiting, instead of blocked (not certain if I have the terms right) and won't start another worker. – tgdavies Dec 25 '22 at 09:43

0 Answers0