I've been scratching my head trying to figure out a hang issue with Java Timers. I was wondering if someone here could help out. Any help in diagnosing the issue is highly appreciated.
I have a simple program with three TimerTask classes (A, B, and Stopper). A and B run repeatedly every 400ms and 500ms respectively. Stopper task is scheduled to run at 2sec to shutdown everything. The timers fire as expected, and the run() methods of tasks execute as expected. However, once the stopper task executes, I expect the program to terminate, but it just hangs after printing "All tasks and timers canceled, exiting". I've tried using jstack to diagnose the problem but there is nothing obvious that indicates what, if anything needs to be released/stopped/canceled etc.
Here is my code:
package com.example.experiments;
import java.util.Date;
/**
* A test timer class to check behavior of exit/hang issues
*/
public class TimerTest {
TimerTest(){
}
class TaskA extends java.util.TimerTask {
TaskA(){
}
public void run() {
System.err.println("A.run() called.");
if (!running){
System.err.println("A: calling this.cancel().");
this.cancel();
return;
}
}
public boolean cancel(){
System.err.println("Canceling TaskA");
return super.cancel();
}
}
class TaskB extends java.util.TimerTask {
TaskB(){
}
public void run(){
System.err.println("B.run() called.");
if (!running){
System.err.println("B: calling this.cancel().");
this.cancel();
return;
}
}
public boolean cancel(){
System.err.println("Canceling TaskB");
return super.cancel();
}
}
private void start(){
this.running = true; // Flag to indicate if the server loop should continue running or not
final java.util.Timer timerA = new java.util.Timer();
final TaskA taskA = new TaskA();
timerA.schedule(taskA, 0, 400);
final java.util.Timer timerB = new java.util.Timer();
final TaskB taskB = new TaskB();
timerB.schedule(taskB, 0, 500);
class StopperTask extends java.util.TimerTask {
private java.util.Timer myTimer;
StopperTask(java.util.Timer timer){
myTimer = timer;
}
public void run(){
taskA.cancel();
taskB.cancel();
timerA.cancel();
timerB.cancel();
this.cancel();
myTimer.cancel();
System.err.println("Stopper task completed");
}
}
final java.util.Timer stopperTimer = new java.util.Timer();
final StopperTask stopperTask = new StopperTask(stopperTimer);
stopperTimer.schedule(stopperTask, 2*1000);
/** Register witjh JVM to be notified on when the JVM is about to exit */
java.lang.Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
System.err.println("shutting down...");
running = false;
taskA.cancel();
taskB.cancel();
timerA.cancel();
timerB.cancel();
stopperTask.cancel();
stopperTimer.cancel();
System.err.println("All tasks and timers canceled, exiting");
System.exit(0);
}
});
}
public static void main(String[] args) {
new TimerTest().start();
}
private boolean running = false;
}