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

ForkJoinTask.get(timeout) Might Wait Forever

    Details

    • Subcomponent:
    • Understanding:
      Fix Understood
    • Introduced In Build:
      b01
    • Introduced In Version:
      11
    • CPU:
      generic
    • OS:
      generic

      Description

      ADDITIONAL SYSTEM INFORMATION :
      Generic

      A DESCRIPTION OF THE PROBLEM :
      The documentation for ForkJoinTask.get(long, TimeUnit) says:
      > Waits if necessary for at most the given time for the computation to complete, and then retrieves its result, if available.
      See https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/ForkJoinTask.html#get(long,java.util.concurrent.TimeUnit)

      However, there's a condition where it will wait forever! See the line here where we try to unpush the runnable then run it in the current thread. If we succeed in unpushing the runnable and running it in the current thread, then the timeout will not fire at all because there is no context with which to fire the timeout. See https://hg.openjdk.java.net/jdk/jdk11/file/1ddf9a99e4ad/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java#l1044

      I can't understand how that could be expected given the documentation that the method guarantees that it should wait for no longer than the timeout passed in.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Here's some code that replicates the issue.


      package ...;

      import java.util.concurrent.ForkJoinPool;
      import java.util.concurrent.ForkJoinTask;
      import java.util.concurrent.TimeUnit;

      public class TimeoutTest {
        public static void main(String[] args) throws Exception {

          ForkJoinTask task1 = ForkJoinPool.commonPool().submit(
              () -> {
                try {
                  Thread.sleep(5000L);
                } catch (InterruptedException ex) {
                  System.out.println("Got interrupted!");
                  return;
                }
                System.out.println("Did not get interrupted!");
              });
          try {
            task1.get(1, TimeUnit.SECONDS);
          } finally {
            task1.cancel(true);
          }
        }
      }



      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      It should display "Got interrupted!" every time.
      ACTUAL -
      It sometimes displays "Got interrupted!" and sometimes displays "Did not get interrupted!".

      ---------- BEGIN SOURCE ----------
      See above.
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      I can use CountDownLatch to ensure that a thread is always created, but that's a pretty bulky solution.

        Attachments

          Activity

            People

            • Assignee:
              martin Martin Buchholz
              Reporter:
              webbuggrp Webbug Group
            • Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

              Dates

              • Created:
                Updated: