scheduleAtFixedRate() を実行中のタスク側から停止する
Javaで、一定時間ごとに実行するプログラムをかく必要があったのでjava.util.concurrentのScheduledExecutorServiceを利用してプログラムを書いた。
一定時間ごとの実行についてはscheduleAtFixedRate()を使って難なく書けた。
しかし、このとき実行されるタスクが異常終了した場合に、定期的な実行を停止するように書きたかったのだがそこでちょっと引っかかった。
scheduleAtFixedRate()のドキュメントによると、
いずれかのタスク実行が例外に遭遇すると、後続の実行は抑制されます。
と書かれてある。
でも、scheduleAtFixedRate()に渡すタスクはRunnable。
Runnable.run()って例外スローできないよね?じゃ、どうやって例外スローするのさ。
と、ここまで考え至って思いついたのは、throws宣言を書かなくてもいいThrowableなクラス、Errorを投げればいいんじゃないか?ということ。
これでうまくいくか下のソースを書いて試してみた。
public class ScheduledAtFixedRateTest { public static void main(String[] args) { ScheduledExecutorService exSvc = Executors.newSingleThreadScheduledExecutor(); final ScheduledFuture<?> f = exSvc.scheduleAtFixedRate(new Runnable() { int execCnt = 0; @Override public void run() { System.out.println("[" + ++execCnt + "]" + new Date()); if(execCnt>=2) throw new Error(); //2回超えたらストップ } }, 2, 2, TimeUnit.SECONDS); //2秒毎に実行 exSvc.schedule(new Callable<Boolean>() { @Override public Boolean call() throws Exception { return f.cancel(true); } }, 10, TimeUnit.SECONDS); //10秒後に停止 System.out.println("StartTime = " + new Date()); while(!f.isDone()) { try { Thread.sleep(10); } catch (InterruptedException e) { // TODO 自動生成された catch ブロック e.printStackTrace(); } } exSvc.shutdown(); System.out.println("EndTime = " + new Date()); } }
結果:
StartTime = Tue Mar 23 07:09:03 JST 2010 [1]Tue Mar 23 07:09:05 JST 2010 [2]Tue Mar 23 07:09:07 JST 2010 EndTime = Tue Mar 23 07:09:07 JST 2010
10秒後の停止ではなく、2回目の実行でうまく停止した様子。
今回はこのやり方で書いてみるが、この使い方、正しいんだろうか?