Java タイマーのハングの問題を解決しようとして頭を悩ませています。ここで誰かが助けてくれるかどうか疑問に思っていました。問題を診断する際の助けをいただければ幸いです。
3 つの TimerTask クラス (A、B、Stopper) を持つ単純なプログラムがあります。A と B は、それぞれ 400ms と 500ms ごとに繰り返し実行されます。ストッパー タスクは、すべてをシャットダウンするために 2 秒で実行されるようにスケジュールされています。タイマーは期待どおりに起動し、タスクの run() メソッドは期待どおりに実行されます。ただし、ストッパータスクが実行されると、プログラムが終了することを期待していますが、「すべてのタスクとタイマーがキャンセルされ、終了しています」と出力した後にハングします。jstack を使用して問題を診断しようとしましたが、何をリリース/停止/キャンセルする必要があるかなどを示す明らかなものはありません。
これが私のコードです:
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;
}