タイマーネタが続いていますが、Java Concurrentパッケージを使ったTimerもできる。どのタイマーも長所と短所があるので、用途に応じてどれを利用すれば良いか決めればよいだろう。
Java Concurrentパッケージを使ったTimerは、java.util.concurrent.ScheduledExecutorServiceを使えば実現できる。Timerの変わりにScheduledExecutorServiceオブジェクトのschedulerを使って、停止させるときにはこの返却値のScheduledFutureオブジェクトのcancelを呼んでいる。stopメソッドをtaskのrunメソッドから呼び出しているあたりで参照関係が気になるかもしれないが、とりあえずサンプルなのでこうしている。schedulerの終了処理についても記載しておきたかったので、メインスレッドで12秒待機してからshutdownNowするコードにしてある。
package org.sssg.soft.sample.timer;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
public class SimpleConcurrentTimer {
private final static long PERIOD = 1000L;
private Runnable task;
private ScheduledExecutorService scheduler;
private ScheduledFuture<?> future;
private final static int COUNT = 10;
public SimpleConcurrentTimer() {
task = new Runnable() {
int i = COUNT;
public void run() {
System.out.println(i--);
if (i < 0) {
stop();
}
}
};
scheduler = Executors.newSingleThreadScheduledExecutor();
}
public void stop() {
scheduler.schedule(new Runnable() {
public void run() {
future.cancel(true);
System.out.println("future canceled");
}
}, 0, TimeUnit.SECONDS);
}
public void run() {
System.out.println("future start");
future = scheduler.scheduleAtFixedRate(task, 0, PERIOD,
TimeUnit.MILLISECONDS);
try {
Thread.sleep(12 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
scheduler.shutdownNow();
System.out.println("shutdowned");
}
public static final void main(final String[] args) {
SimpleConcurrentTimer app = new SimpleConcurrentTimer();
app.run();
}
}
ちなみに、Executorオブジェクトは、Executorsのstaticなファクトリ・メソッドを使って生成できる。ScheduledExecutorにはnewScheduledThreadPoolやnewSingleThreadScheduledExecutorがある。前者はスレッドプールを作ることから複数スレッド対応版で、後者は単一スレッド対応版のScheduledExecutorオブジェクトの生成となる。ここでは、newSingleThreadScheduledExecutorを使っている。