-
Bug
-
Resolution: Fixed
-
P4
-
7u79, 9, 10, 11, 12
-
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);
}
}
}
}
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);
}
}
}
}
- duplicates
-
JDK-8200284 Thread.join(long millis) waits longer than expected if system date is modified
-
- Closed
-