javamultithreadingexecutorservicethread-sleepforkjoinpool

Behaviour of Threads during blocking IO in Java ForkJoinPool


If the Thread inside the ForkJoinPool does a blocking I/O activity ( simulated below in code using Thread.sleep(10000)) , it should pick up another task which is not causing blocking IO. However, running below code with parallelism of 1 or 2 with ForkJoinPool the results don't match it. The Thread doesn't relinquish the blocking task(i.e task 1 and task2 ) and moves to non blocking ( task 3 ). In case of pool size =1 , all tasks execute in sequence whereas I expected Task 3 to complete first as it was non blocking in both cases ( pool size=1 or 2)

What is the actual behaviour of Threads in ForkJoinPool in case of blocking IO ?

    ForkJoinPool pool = new  ForkJoinPool(1);
    
    List<Future<String>> tasks = new ArrayList<Future<String>>();
    

    //Blocking
    tasks.add(pool.submit(() ->  {  Thread.sleep(10000); System.out.println("Task 1 woke up"+ Thread.currentThread().isDaemon()); return "task1"; }));
    //Blocking
    tasks.add(pool.submit(() ->  { Thread.sleep(10000); System.out.println("Task 2 woke up"+Thread.currentThread().isDaemon()); return "task2"; }));
    //Non Blocking
    tasks.add(pool.submit(() ->  {  System.out.println("Task 3 Runs"+Thread.currentThread().isDaemon()); return "task3"; }));
    

    
    int i=0;
    System.out.println("pool size = " + pool.getParallelism() + "Thread count=" +pool.getPoolSize() + "Stealing =" + pool.getStealCount());
    System.out.println("waiting");
    
    String str1 = tasks.get(0).get();
    String str2 = tasks.get(1).get();
    String str3 = tasks.get(2).get();
    
    System.out.println("Results = " +  str1+ str2 +str3);
    
    System.out.println("done");

Results :

//Pool size = 2
Task 2 woke uptrue
Task 1 woke uptrue
Task 3 Runstrue

//Pool size = 1
Task 1 woke uptrue
Task 2 woke uptrue
Task 3 Runstrue

Another observation:
When we submit Task 3( non blocking ) first then only it is invoked first.


Solution

  • ForkJoinPool is used only as a scheduler as mentioned in the Loom Proposal. Only Virtual Threads have the ability to relinquish the blocking task and switch to another task. Based on what I remember from reading a mail in the loom mailing list, the loom team is currently not planning to redesign java.util.concurrent's ForkJoinPool to use Virtual Threads.