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

[OS_X] ConditionObject#awaitNanos waits too long if system clock is turned back

XMLWordPrintable

      FULL PRODUCT VERSION :
      java version "1.7.0_79"
      Java(TM) SE Runtime Environment (build 1.7.0_79-b15)
      Java HotSpot(TM) 64-Bit Server VM (build 24.79-b02, mixed mode)

      ADDITIONAL OS VERSION INFORMATION :
      Darwin Kernel Version 15.0.0: Wed Aug 26 16:57:32 PDT 2015; root:xnu-3247.1.106~1/RELEASE_X86_64 x86_64

      EXTRA RELEVANT SYSTEM CONFIGURATION :
      should not matter, the problem is obvious from the source code

      A DESCRIPTION OF THE PROBLEM :
      the method java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject#awaitNanos has a Problem in cases where the system time is turned back by several minutes.

      The source code of the method illustrates this when you consider a case where the system clock is turned back

       public final long awaitNanos(long nanosTimeout)
                      throws InterruptedException {
                  if (Thread.interrupted())
                      throw new InterruptedException();
                  Node node = addConditionWaiter();
                  int savedState = fullyRelease(node);
                  long lastTime = System.nanoTime();
                  int interruptMode = 0;
                  while (!isOnSyncQueue(node)) {
                      if (nanosTimeout <= 0L) {
                          transferAfterCancelledWait(node);
                          break;
                      }
                      LockSupport.parkNanos(this, nanosTimeout);
                      if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                          break;

                      long now = System.nanoTime();
                      nanosTimeout -= now - lastTime;
                      lastTime = now;
                  }

      basically line tries to reduce the timeout by a negative number (in case the clock was turned back) which ends up increasing the wait time. So if the clock was turned back by 10 minutes then the call to

      awaitNanos(10 * 1000 * 1000)

      will end up waiting for 10 minutes and 10 seconds instead of the requested 10 seconds.

      Java 8s implementation seems to handle this problem properly.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1. record the current system time
      2. start call awaitNanos on the condition object with a timeout of 10 seconds
      3. turn back the clock for 10 minutes


      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      Expected: awaitNanos returns after 10s

      ACTUAL -
      Actual: awaitNanos returns after 10 minutes 10s


      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      package eu.emundo;

      import java.util.concurrent.ArrayBlockingQueue;
      import java.util.concurrent.TimeUnit;

      public class Main {

          public static void main(String[] args) {
              final ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<String>(1);

              long startTime = System.currentTimeMillis();
              System.err.println("starting to wait " + startTime);
              try {
                  queue.poll(10, TimeUnit.SECONDS);
                  long endTime = System.currentTimeMillis();
                  System.err.println("done waiting " + endTime+ " delta: " + ((endTime - startTime) / 1000) + "s");
              } catch (Exception e) {
                  e.printStackTrace();
              } finally {
                  System.err.println("DONE");
              }
          }
      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      none on Java 7

            psonal Pallavi Sonal (Inactive)
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: