Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8301216

ForkJoinPool invokeAll() ignores timeout

    XMLWordPrintable

Details

    • b05
    • 17
    • b01
    • generic
    • generic

    Backports

      Description

        A DESCRIPTION OF THE PROBLEM :
        Whenever using ForkJoinPool executor and calling invokeAll() method with a timeout less than the time the task takes to execute, it won't cancel the last task (or single), it just executes it until completion.

        This bug was observed in any release of Java 17 only.

        REGRESSION : Last worked in version 16

        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        If the task sleep timer is greater than the timeout set, the task should always timeout.
        I have provided a source code scratch file to test this behaviour. If you run it with Java 11,12,13,14,15,16 or even 19. The console should always print "TASK TIMED OUT" (if it's setup with sleep greater than the timeout).

        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        For all Callable tasks to be timed out. This is observed by "TASK TIMED OUT" being printed on the console for the number of tasks in the list.
        ACTUAL -
        The last or single (if only 1 passed to the list) task will print "TASK SUCCESSFULLY EXECUTED" on the console.

        ---------- BEGIN SOURCE ----------
        import java.util.List;
        import java.util.concurrent.*;

        class Scratch {

            static final int TIME_OUT = 1000;
            static final TimeUnit TIME_OUT_UNIT = TimeUnit.MILLISECONDS;
            static final int TASK_SLEEP = 2000;
            
            public static void main(String[] args) {

                System.out.println("JVM: " + System.getProperty("java.version"));

                ExecutorService threadPool = new ForkJoinPool(3); // incorrect behaviour in Java 17
        // ExecutorService threadPool = Executors.newWorkStealingPool(); // incorrect behaviour in Java 17
        // ExecutorService threadPool = Executors.newFixedThreadPool(3); // works in Java 17

                Callable<String> simpleCallableTask = () -> {
                    Thread.sleep(TASK_SLEEP); // task duration
                    return "Return task result";
                };

                List<Callable<String>> callableList = List.of(simpleCallableTask, simpleCallableTask, simpleCallableTask);

                try {
                    List<Future<String>> futureList = threadPool.invokeAll(callableList, TIME_OUT, TIME_OUT_UNIT);
                    for (Future<String> future : futureList) {
                        if (future.isCancelled()) {
                            System.out.println("TASK TIMED OUT");
                        } else {
                            System.out.println("TASK SUCCESSFULLY EXECUTED");
                        }
                    }
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        ---------- END SOURCE ----------

        CUSTOMER SUBMITTED WORKAROUND :
        It's mentioned with comments on the source code, but a workaround is not using ForkJoinPool at all, just use Executors.newFixedThreadPool(n)

        FREQUENCY : always


        Attachments

          Issue Links

            Activity

              People

                wxiao Weibing Xiao
                webbuggrp Webbug Group
                Votes:
                0 Vote for this issue
                Watchers:
                7 Start watching this issue

                Dates

                  Created:
                  Updated:
                  Resolved: