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

FutureTask bullet-proofing

    XMLWordPrintable

Details

    • Bug
    • Resolution: Cannot Reproduce
    • P4
    • None
    • 5.0
    • core-libs

    Description

      the jdk7 implementation of FutureTask has small correctness issues
      with state transition. If we look at innerRun

              void innerRun() {
                  if (!compareAndSetState(READY, RUNNING))
                      return;

      //// Suppose cancel is invoked and returns here.

      //// At this point, isDone() returns true.

                  runner = Thread.currentThread();

      //// At this point, isDone() returns false.

                  if (getState() == RUNNING) { // recheck after setting thread


      we have a case where isDone() could return false after cancel() returns,
      even though isCancelled() returns true.

      It's the old problem of having state transitions recorded in two
      separate fields, when we can only update one of them atomically.
      We can make the races rarer, but I'm not sure we can eliminate them
      without moving all significant state into the one monotonically
      incremented CASable int.

      -----

      There's the other problem of interrupt delivery.
      It is not absolutely guaranteed that cancel(true) will indeed interrupt
      the task instead of its surrounding code.

      -----

      I believe both of the above problems by designing
      state transitions very carefully, without any additional overhead for
      the "normal" case of successful run().

      Perhaps there's a general principle here that any class which can
      be designed to have an ordered set of states with monotonically
      increasing transitions doesn't need locks, only CAS.

      I think we can solve the incorrectly delivered interrupt problem
      by (as usual) introducing a new state INTERRUPTING, with cancel()
      transitioning RUNNING -> INTERRUPTING -> CANCELLED.

      If the runner thread notices that state == INTERRUPTING, it must
      wait (via acquireShared) for the state to first advance to CANCELLED,
      before returning from run().

      If we keep track of whether an interrupt has been
      delivered, we can guarantee that it was delivered in a specific window,
      which would allow us to reconsider restoring interrupt state.

      In addition, I believe this can be done while supporting set() called
      independently, that is, not directly from run(), without any extra
      CAS state transitions in the normal case. See:

      6663476: FutureTask.get() may return null if set() is not called from run()

      Attachments

        Issue Links

          Activity

            People

              martin Martin Buchholz
              martin Martin Buchholz
              Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:
                Imported:
                Indexed: