Loading... (original) (raw)
FULL PRODUCT VERSION :
java version "1.6.0_10"
Java(TM) SE Runtime Environment (build 1.6.0_10-b33)
Java HotSpot(TM) Client VM (build 11.0-b15, mixed mode, sharing)
java version "1.7.0-ea-fastdebug"
Java(TM) SE Runtime Environment (build 1.7.0-ea-fastdebug-b58)
Java HotSpot(TM) Client VM (build 16.0-b02-fastdebug, mixed mode)
A DESCRIPTION OF THE PROBLEM :
ReferenceQueue.remove(timeout) may return null even if given timeout period has not expired.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
ReferenceQueue.remove(timeout) should wait until either next reference object in this queue becomes available or the given timeout period expires, but not earlier or far later.
ACTUAL -
Exception in thread "main" java.lang.Error: timeout: 5000; actual time: 1000
at Main.main(Main.java:38)
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
public class Main extends Thread {
static ReferenceQueue queue = new ReferenceQueue();
static Object referent = new Object();
static WeakReference reference = new WeakReference(referent, queue);
long timeout;
long actual;
boolean suspect;
Main(long timeout) {
this.timeout = timeout;
}
public static void main(String... args) throws Exception {
final int LONG_TIMEOUT = 5000;
final int SHORT_WAIT_TIME = 1000;
final int TOLERANCE = 1000;
assert LONG_TIMEOUT > SHORT_WAIT_TIME : "Bad initial parameters";
assert LONG_TIMEOUT - SHORT_WAIT_TIME > TOLERANCE : "Bad initial parameters";
Main[] threads = new Main[2];
for (int i = 0, n = threads.length; i < n; ++i) {
threads[i] = new Main(LONG_TIMEOUT);
threads[i].start();
}
Thread.sleep(SHORT_WAIT_TIME);
referent = null;
System.gc();
for (Main thread : threads) {
thread.join();
}
for (Main thread : threads) {
if (thread.suspect && Math.abs(thread.timeout - thread.actual) > TOLERANCE) {
throw new Error("timeout: " + thread.timeout + "; actual time: " + thread.actual);
}
}
}
public void run() {
try {
long start = System.currentTimeMillis();
Reference<?> reference = queue.remove(timeout);
actual = System.currentTimeMillis() - start;
suspect = reference == null;
} catch (InterruptedException exc) {
exc.printStackTrace();
}
}
}
---------- END SOURCE ----------