Timerの実装
java.util.Timer
でタイマーを実装することができますが、ほかにも
java.util.concurrent.Executors;
java.util.concurrent.ScheduledExecutorService;
を使って実装することも可能です。
記事の目的
タイマーで次のように10ms間隔でタスクを定期実行するよう設定した場合、
import java.util.Timer;
public class TimerTest {
public static void main(String[] args) {
// Timerクラスのオブジェクトを作成
Timer time = new Timer();
time.scheduleAtFixedRate(new SampleTask(), 0, 10);
}
}
import java.util.TimerTask;
public class SampleTask extends TimerTask {
public long before_time;
public void run() {
long now_time = System.currentTimeMillis();
System.out.print("interval time[ms] ");
System.out.println(now_time - before_time);
before_time = now_time;
}
}
結果
interval time[ms] 15
interval time[ms] 16
interval time[ms] 0
interval time[ms] 16
interval time[ms] 15
interval time[ms] 0
interval time[ms] 16
interval time[ms] 16
interval time[ms] 0
interval time[ms] 16
interval time[ms] 0
interval time[ms] 16
interval time[ms] 16
interval time[ms] 0
interval time[ms] 16
interval time[ms] 16
interval time[ms] 0
interval time[ms] 15
interval time[ms] 0
interval time[ms] 16
interval time[ms] 16
interval time[ms] 0
interval time[ms] 15
interval time[ms] 15
interval time[ms] 0
interval time[ms] 15
インターバル間隔は15msや0msなど不安定です。
ここが、大きな問題です。
ちなみに
Timer.scheduleAtFixedRate
でタスクを設定した場合、タスクがインターバル間隔以上に時間がかかったりすると、すぐ実行してしまったりします。
こちらの方の説明が非常にわかりやすいです。
Executor.scheduleWithFixedDelay
を使用すれば固定間隔で使用できます。
ScheduledExecutorService: サンプルコード
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ScheduledThread {
public static void main(String[] args){
ScheduledExecutorService executor = Executors.newScheduledThreadPool(15);
ScheduledWork work1 = new ScheduledWork();
//executor.scheduleAtFixedRate(work1, 0,1, TimeUnit.MILLISECONDS);
executor.scheduleWithFixedDelay(work1, 0,100, TimeUnit.MICROSECONDS);
}
}
public class ScheduledWork implements Runnable{
public long before_time;
@Override
public void run(){
long now_time = System.currentTimeMillis();
System.out.println(now_time - before_time);
before_time = now_time;
}
}
コードの説明
定期実行するインスタンスはインターフェースRunnnableを継承します。Runnnableはrunメソッドを持つクラスのことです。
Executerとは
この中で、
newScheduledThreadPool
の説明は
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
指定された遅延時間後、または周期的にコマンドの実行をスケジュールできる、スレッド・プールを作成します。
パラメータ:
corePoolSize - アイドルであってもプール内に維持されるスレッドの数。
戻り値:
新規生成されたスケジュール済みのスレッド・プール
例外:
IllegalArgumentException - corePoolSize < 0の場合
こちらとなります。
私の理解では、タスク=Executorです
こちらも参考になります。
サンプルコードと結果について
WithFixedDelayで100usで設定した場合、
interval time[ms] 16
interval time[ms] 16
interval time[ms] 0
interval time[ms] 15
interval time[ms] 17
interval time[ms] 15
interval time[ms] 0
interval time[ms] 0
interval time[ms] 16
interval time[ms] 15
interval time[ms] 15
interval time[ms] 16
interval time[ms] 15
interval time[ms] 16
interval time[ms] 15
interval time[ms] 16
interval time[ms] 15
interval time[ms] 15
interval time[ms] 16
interval time[ms] 16
interval time[ms] 16
interval time[ms] 16
interval time[ms] 16
interval time[ms] 16
interval time[ms] 15
interval time[ms] 15
interval time[ms] 16
interval time[ms] 16
interval time[ms] 15
interval time[ms] 15
interval time[ms] 16
interval time[ms] 16
interval time[ms] 15
interval time[ms] 16
interval time[ms] 15
interval time[ms] 16
interval time[ms] 15
interval time[ms] 15
interval time[ms] 1
interval time[ms] 15
interval time[ms] 0
interval time[ms] 16
interval time[ms] 16
interval time[ms] 15
interval time[ms] 16
interval time[ms] 15
interval time[ms] 16
interval time[ms] 16
interval time[ms] 16
こんな感じで結局15msほどで反復実行します。
また、0msなどもあり不安定です。
intervalを30msにすると
interval time[ms] 32
interval time[ms] 31
interval time[ms] 31
interval time[ms] 31
interval time[ms] 31
interval time[ms] 31
interval time[ms] 31
interval time[ms] 30
interval time[ms] 33
interval time[ms] 31
interval time[ms] 32
interval time[ms] 31
interval time[ms] 32
interval time[ms] 32
interval time[ms] 30
interval time[ms] 32
interval time[ms] 31
interval time[ms] 31
interval time[ms] 31
interval time[ms] 31
interval time[ms] 31
interval time[ms] 31
interval time[ms] 32
interval time[ms] 31
interval time[ms] 30
interval time[ms] 31
interval time[ms] 45
interval time[ms] 46
interval time[ms] 45
interval time[ms] 30
interval time[ms] 31
interval time[ms] 31
interval time[ms] 32
interval time[ms] 30
interval time[ms] 46
interval time[ms] 31
interval time[ms] 46
interval time[ms] 31
interval time[ms] 30
interval time[ms] 31
interval time[ms] 31
interval time[ms] 31
30~46msとこれでも微妙に遅かったりちょうどよかったりします。
まとめ
TimerもScheduledExecutorServiceどちらで実装しても、差はありません。
インターバル間隔がms単位の場合、15ms単位の遅れが突如混ざる可能性はどちらでもありえます。