|
Quick Lists
|
|
Bug ID:
|
6639183
|
|
Votes
|
0
|
|
Synopsis
|
Scheduling large negative delay hangs entire ScheduledExecutor
|
|
Category
|
java:classes_util_concurrent
|
|
Reported Against
|
|
|
Release Fixed
|
6u10(b10)
|
|
State
|
10-Fix Delivered,
bug
|
|
Priority:
|
2-High
|
|
Related Bugs
|
6725789
|
|
Submit Date
|
07-DEC-2007
|
|
Description
|
type: bug
product: j2se
sub-cat: java.util.*
release: Java 6
O/S: Windows XP
Synopsis: Scheduling large negative delay hangs entire ScheduledExecutor
Full O/S version: customer Windows XP [Version 5.1.2600]
java -version:
both
java version "1.5.0_12"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_12-b04)
Java HotSpot(TM) Client VM (build 1.5.0_12-b04, mixed mode)
and
java version "1.6.0_03"
Java(TM) SE Runtime Environment (build 1.6.0_03-b05)
Java HotSpot(TM) Client VM (build 1.6.0_03-b05, mixed mode)
Description:
Scheduling something with a very large negative delay (using TimeUnit.MILLISECONDS) blocks the scheduled executor from running anything. Other than perhaps relative ordering, negative delay (no matter how large) is effectively the same as zero delay and the scheduled item ought to be eligible to run immediately.
Frequency: always
Regression: no
Steps to reproduce:
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ScheduleBug {
public static void main(String[] args) {
ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(1);
exec.schedule(new Op("one"), -1000, TimeUnit.MILLISECONDS);
exec.schedule(new Op("two"), -100, TimeUnit.MILLISECONDS);
exec.schedule(new Op("three"), -10, TimeUnit.MILLISECONDS);
exec.schedule(new Op("four"), 0, TimeUnit.MILLISECONDS);
exec.schedule(new Op("five"), 1000, TimeUnit.MILLISECONDS);
exec.schedule(new Op("six"), 5000, TimeUnit.MILLISECONDS);
exec.schedule(new Runnable() {
public void run() { System.exit(0); }
}, 10000, TimeUnit.MILLISECONDS);
}
static class Op implements Runnable {
private final String m_message;
public Op(String message)
{ m_message = message; }
public void run() {
System.out.println(m_message);
System.out.flush();
}
}
}
produces the following output as expected (after 10-15s):
one
two
three
four
five
six
However, change the first schedule line from
exec.schedule(new Op("one"), -1000, TimeUnit.MILLISECONDS);
to
exec.schedule(new Op("one"), Long.MIN_VALUE, TimeUnit.MILLISECONDS);
and the program will hang for hours with no output at all.
problems:
1) should be exact same output.
2) Even if underflow were documented / specified behavior, scheduling op "one" far in the future should NOT prevent other ops from running right away
severity: some customer possible
Posted Date : 2007-12-07 21:06:33.0
|
|
Work Around
|
manually change negative values to zero before scheduling
|
|
Evaluation
|
This is reproducible with jdk 7-b07 and 6u5,
but no longer reproducible in jdk 7-b08
which had a large complex rewrite of much of
ThreadPoolExecutor and ScheduledThreadPoolExecutor
Here's a smaller test case demonstrating the problem:
import java.util.concurrent.ScheduledThreadPoolExecutor;
import static java.util.concurrent.TimeUnit.*;
public class Bug {
public static void main(String[] args) throws Throwable {
ScheduledThreadPoolExecutor pool = new ScheduledThreadPoolExecutor(1);
pool.schedule(new Runnable() { public void run() {
System.out.println("Age of the dinosaurs"); }},
Long.MIN_VALUE, NANOSECONDS);
pool.schedule(new Runnable() { public void run() {
System.out.println("Yesterday, all my troubles ..."); }},
-1L, DAYS);
pool.shutdown();
pool.awaitTermination(10L, SECONDS);
}
}
Here's the list of CRs fixed in jdk 7-b08
6450200: ThreadPoolExecutor idling core threads don't terminate when core pool size reduced
6450205: ThreadPoolExecutor does not replace throwing threads
6450207: ThreadPoolExecutor doesn't count throwing tasks as "completed"
6450211: ThreadPoolExecutor.afterExecute sees RuntimeExceptions, but not Errors
6454289: ScheduledThreadPoolExecutor spins while waiting for delayed tasks after shutdown
6458339: ThreadPoolExecutor very slow to shut down for large poolSize
6458662: ThreadPoolExecutor poolSize might shrink below corePoolSize after timeout
6459119: Explain how afterExecute can access a submitted job's Throwable
I don't know what exactly changed to cause this bug to go away.
Posted Date : 2007-12-07 21:57:20.0
Looking closer....
Changing the Runnable to a Callable
pool.schedule(
new Callable<Void>() { public Void call() {
System.out.println("Age of the dinosaurs");
return null; }},
Long.MIN_VALUE, NANOSECONDS);
makes the bug go away.
Which strongly hints that this easy change make in 7-b08
should be backported:
--- /tmp/geta27573 2007-12-07 14:31:24.283954000 -0800
+++ ScheduledThreadPoolExecutor.java 2007-12-07 14:30:45.394875000 -0800
@@ -355,14 +355,15 @@
}
public ScheduledFuture<?> schedule(Runnable command,
long delay,
TimeUnit unit) {
if (command == null || unit == null)
throw new NullPointerException();
+ if (delay < 0) delay = 0;
long triggerTime = now() + unit.toNanos(delay);
RunnableScheduledFuture<?> t = decorateTask(command,
new ScheduledFutureTask<Boolean>(command, null, triggerTime));
delayedExecute(t);
return t;
}
It appears that this problem is due to large negative values underflowing.
This problem may appear elsewhere in java.util.concurrent.
Posted Date : 2007-12-07 22:34:42.0
David Holmes writes,
"The reason I think it hangs (it's a tricky one to puzzle out) is because the bad Delayed item gets correctly queued at the head of the delay queue, but because of the way the initial delay is stored and the way getDelayed() works, you get an underflow that turns the delay into a large positive value - hence no Delayed entries get processed because this is the one with the next delay and it claims not to be ready."
which makes sense to me.
Posted Date : 2007-12-09 02:37:27.0
Note that the fix for 6725789 subsumes/replaces the simple fix suggested here.
Posted Date : 2008-08-20 10:46:47.0
|
|
Comments
|
PLEASE NOTE: JDK6 is formerly known as Project Mustang
|
|
|
 |