定期的なタスクを実行するために、私は Timer
と ScheduledThreadPoolExecutor
(単一のスレッドで)を見て、後者を使用することにしました。 reference for Executors.newSingleThreadScheduledExecutor()
、それは言う:
ただし、シャットダウン前の実行中に障害が発生したためにこの単一スレッドが終了した場合、後続のタスクを実行する必要がある場合は、新しいスレッドが代わりに使用されることに注意してください。
私の計画は、これを、他の操作を監視したいウォッチドッグコードのキャッチされない例外に対する保護手段として使用することでした。確認したかったので、以下のテストを作成しましたが、すぐに失敗しました。私は間違った仮定をしていたようです、または私のテストについて何か間違っていますか?
コードは次のとおりです。
@Test
public void testTimer() {
final AtomicInteger cTries = new AtomicInteger(0);
final AtomicInteger cSuccesses = new AtomicInteger(0);
TimerTask task = new TimerTask() {
@Override
public void run()
{
cTries.incrementAndGet();
if (true) {
throw new RuntimeException();
}
cSuccesses.incrementAndGet();
}
};
/*
Timer t = new Timer();
t.scheduleAtFixedRate(task, 0, 500);
*/
ScheduledExecutorService exe = Executors.newSingleThreadScheduledExecutor();
exe.scheduleAtFixedRate(task, 0, 500, TimeUnit.MILLISECONDS);
synchronized (this) {
try {
wait(3000);
} catch (InterruptedException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
exe.shutdown();
/*
t.purge();
*/
Assert.assertEquals(cSuccesses.get(), 0);
Assert.assertTrue(cTries.get() > 1, String.format("%d is not greater than 1. :(", cTries.get()));
}
繰り返されるタスクがキャッチされない例外をスローすると、それは死亡したか、エラー状態にあると見なされます。将来を調べてエラー/例外を取得しない限り、サイレントに失敗するのもちょっとした落とし穴です。
繰り返しのタスクを強制終了したくない場合は、例外をキャッチする必要があります。
マットbが上記のコメントで指摘しているように
このようなフレームワークコードが失敗したジョブを安全に再開できると想定するのは問題があります-例外で失敗したという事実は、データが何らかの状態のままになっている可能性があることを意味し、潜在的に再起動するのは安全ではありませんジョブ。
matt bが理由を示しています。
このようなフレームワークコードが失敗したジョブを安全に再開できると想定するのは問題があります-例外で失敗したという事実は、データが何らかの状態のままになっている可能性があることを意味し、潜在的に再起動するのは安全ではありませんジョブ。
ScheduledExecutorService のドキュメントに記載されていることに注意してください。
タスクの実行で例外が発生した場合、それ以降の実行は抑制されます。
そしてMichael Krusseが言うように、新しいスレッドを作成することについてのポイントは、他のタスクが実行を継続できるようにすることです。