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

Thread.join(ms) on Linux still affected by changes to the time-of-day clock

XMLWordPrintable

    • b12
    • x86_64
    • linux
    • Not verified

      FULL PRODUCT VERSION :
      OpenJDK Runtime Environment (fedora-2.5.5.5-x86_64 u79-b13)
      OpenJDK 64-Bit Server VM (build 24.79-b02, mixed mode)


      ADDITIONAL OS VERSION INFORMATION :
      Linux localhost 3.14.39-nrj-desktop-5rosa.lts-x86_64 #1 SMP PREEMPT Wed Apr 29 14:58:30 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux


      A DESCRIPTION OF THE PROBLEM :
      This is continuation of 6900441. That bug fix get Thread.sleep(SLEEP_TIME) и Object.wait(SLEEP_TIME) working correctly with time shifts, but Thread.join(SLEEP_TIME) still affected by clock changes.

      Replacing System.currentTimeMillis() with System.nanoTime() in Thread.join(long millis) fixes the issue.


      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1. Start long-running thread.
      2. Invoke thread.join(60 * 1000) // with one minute timeout
      3. Set clock back to 10 minutes or so.



      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      Thread.join should exit after specified timeout.
      ACTUAL -
      Thread.join waits for absolute time, but not for relative time interval.


      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      // Name: TimeJumpWithThreadJoin.java
      //
      import java.io.IOException;
      import java.util.concurrent.TimeUnit;

      public class TimeJumpWithThreadJoin {
          public static void main(String[] args) throws InterruptedException {
              SleepWorker thread = new SleepWorker("Worker0");
              thread.start();
              System.out.println("Waiting for thread join (should last for one minute)...");
              System.out.println("Meantime, set your system clock back (for ten minutes, for example) and measure time (on real clock) till Thread.join ended.");
              thread.join(60 * 1000);
              System.out.println("Thread.join ended().");
              if (thread.isAlive()) {
                  thread.interrupt();
              }
              System.out.println("Done.");
          }
      }

      class SleepWorker extends Thread {
          static final public int SLEEP_TIME = 60 * 60 * 1000; // 1 hour
          public SleepWorker(String name) {
              super(name);
          }

          public void run() {
              System.out.println("Thread goes to sleep.");
              try {
                  Thread.sleep(SLEEP_TIME);
              } catch (InterruptedException ie) {
                  System.out.println("Thread sleep interrupted.");
              }
              System.out.println("SleepWorker: '" + getName() + "' is done.");
          }
      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Working workaround:

              thread.joinx(60 * 1000);

      class SleepWorker extends Thread {
      ...
          synchronized void joinx(long millis)
              throws InterruptedException {
              long base = System.nanoTime();
              long now = 0;

              if (millis < 0) {
                  throw new IllegalArgumentException("timeout value is negative");
              }

              if (millis == 0) {
                  while (isAlive()) {
                      wait(0);
                  }
              } else {
                  while (isAlive()) {
                      long delay = millis - now;
                      if (delay <= 0) {
                          break;
                      }
                      wait(delay);
                      now = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - base);
                  }
              }
          }
      }


            rriggs Roger Riggs
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated:
              Resolved: