-
Bug
-
Resolution: Fixed
-
P3
-
8u45
-
b78
-
x86_64
-
windows_7
Issue | Fix Version | Assignee | Priority | Status | Resolution | Resolved In Build |
---|---|---|---|---|---|---|
JDK-8135824 | emb-9 | Semyon Sadetsky | P3 | Resolved | Fixed | team |
JDK-8161797 | 8u112 | Anton Litvinov | P3 | Resolved | Fixed | b03 |
JDK-8156308 | 8u111 | Anton Litvinov | P3 | Resolved | Fixed | b01 |
JDK-8148959 | 8u102 | Anton Litvinov | P3 | Resolved | Fixed | b01 |
JDK-8151096 | 8u101 | Anton Litvinov | P3 | Resolved | Fixed | b01 |
JDK-8153428 | 8u92 | Anton Litvinov | P3 | Resolved | Fixed | b31 |
JDK-8150448 | 8u74 | Anton Litvinov | P3 | Resolved | Fixed | b32 |
JDK-8162147 | emb-8u111 | Anton Litvinov | P3 | Resolved | Fixed | b01 |
JDK-8155456 | emb-8u101 | Anton Litvinov | P3 | Resolved | Fixed | b01 |
JDK-8163051 | openjdk7u | Anton Litvinov | P3 | Resolved | Fixed | master |
A DESCRIPTION OF THE PROBLEM :
There is a logic bug in javax.swing.TimerQueue.
The result is that a timer with a long delay prevent
other timers with shorter delays to get fired.
I have include a test case. It runs 30-60 seconds, then prints "Delay abnormal: XXX"
and JVM exit with 1.
Sequence of the test:
1) 80 short delay repeating timers are started with a delay of 100ms.
The action listener check if it get invoked every 100ms.
If the delay is more than 5 seconds, it prints "Delay abnormal: XXX" and exit the JVM.
2) one repeating timer is started which changes his own delay from short to long and back if it get fired.
If this timer changes from short back to long delay, it will stress the TimerQueue with "start" calls.
This timer with dynamic delay cause a logic bug in TimerQueue.
This can be reproduced with the latest Java 8 (u45) and Java 7 (u79/80) version
Explanation of the logic bug:
Method TimerQueue#run() (executed by the TimerThread) does this:
Line 171: Timer timer = queue.take().getTimer();
Line 172: timer.getLock().lock();
Line 171 waits for the timer with the shortest delay and remove it.
After the timer is removed from the queue, the timer is locked (line 172).
It's possible that TimerQueue#addTimer(Timer, long) is invoked (by the EDT)
"between" Line 171 and Line 172. At this moment, the timer is not locked
so addTimer is not prevented to add the (same) timer instance to the queue.
If the timer reference in run() and addTimer() points to the same timer instance, everything gets bad:
The timer is now in the queue and TimerQueue#run() will:
a) add the timer again to the queue -> The queue contains the same timer instance more than once.
b) changes the time "DelayedTimer.time" by setTime -> The order of the PriorityQueue is incorrect
Possible solution:
Introduce a separate Lock which guarantee that this code from TimerQueue#addTimer(Timer, long):
if (! containsTimer(timer)) {
addTimer(..);
}
is NOT invoked while the TimerThread "remove and lock" the timer (Line 171/172).
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the testcase with Java 8 or Java 7 and wait 30-60 seconds
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Testcase should run forever
ACTUAL -
Testcase runs 30-60 seconds, then prints "Delay abnormal: XXX" and JVM exit with 1
REPRODUCIBILITY :
This bug can be reproduced often.
---------- BEGIN SOURCE (updated from another similar report) ----------
import javax.swing.Timer;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class TimerQueueBug {
public static void main(String[] args) throws Exception{
for (int i = 0; i < 80; i++) {
startShortTimer();
}
final boolean[] longDelay = new boolean[1];
final Timer dyn = new Timer(100, null);
dyn.addActionListener( new ActionListener() {
@Override
public void actionPerformed( ActionEvent e ) {
try {
if ( longDelay[0] ) {
dyn.setDelay(50);
dyn.start();
} else {
dyn.setDelay(500);
for ( int i = 0; i < 100; i++ ) {
dyn.start();
}
}
longDelay[0] = !longDelay[0];
} catch ( Throwable ex ) {
ex.printStackTrace();
System.exit(99);
}
}
} );
dyn.setRepeats(true);
dyn.start();
while (true) {
Thread.sleep(1);
}
}
private static void startShortTimer() {
final int delay = 100;
Timer t = new Timer( delay, new ActionListener() {
long nextActionExpectedAt;
@Override
public void actionPerformed( ActionEvent e ) {
if (nextActionExpectedAt != 0) {
final long diff = System.currentTimeMillis() - nextActionExpectedAt;
if (diff > 400) {
System.out.println("Delay abnormal: " + diff);
System.exit(1);
}
}
nextActionExpectedAt = System.currentTimeMillis() + delay;
}
} );
t.setRepeats(true);
t.start();
}
}
---------- END SOURCE ----------
- backported by
-
JDK-8135824 javax.swing.TimerQueue: timer fires late when another timer starts
- Resolved
-
JDK-8148959 javax.swing.TimerQueue: timer fires late when another timer starts
- Resolved
-
JDK-8150448 javax.swing.TimerQueue: timer fires late when another timer starts
- Resolved
-
JDK-8151096 javax.swing.TimerQueue: timer fires late when another timer starts
- Resolved
-
JDK-8153428 javax.swing.TimerQueue: timer fires late when another timer starts
- Resolved
-
JDK-8155456 javax.swing.TimerQueue: timer fires late when another timer starts
- Resolved
-
JDK-8156308 javax.swing.TimerQueue: timer fires late when another timer starts
- Resolved
-
JDK-8161797 javax.swing.TimerQueue: timer fires late when another timer starts
- Resolved
-
JDK-8162147 javax.swing.TimerQueue: timer fires late when another timer starts
- Resolved
-
JDK-8163051 javax.swing.TimerQueue: timer fires late when another timer starts
- Resolved
- duplicates
-
JDK-8130736 javax.swing.TimerQueue: timer fires late when another timer starts
- Closed
-
JDK-8146334 Backport 8130735 to Java 8u
- Closed
-
JDK-8146334 Backport 8130735 to Java 8u
- Closed