◆PROCESSING 逆引きリファレンス
カテゴリー:制御系
一定時間後に処理を行うには(Timer編)
【概要】
以前、PROCESSINGで一定時間後に処理を行う方法(一定時間後に処理を行うには)を紹介させてもらいました。
該当記事の中でマルチスレッドを使った時間計測について紹介をさせてもらいましたが、より汎用的なTimerクラスを使った方法もあるので、追加で紹介させてもらいたいと思います。
Timerクラスを使う方法もマルチスレッドを用いる方法の1つになりますが、thread()命令でマルチスレッドを行うよりも、簡単に呼び出せるので便利です。
Javaで利用可能なTimerには、java.util.Timer、javax.swing.Timer、javax.management.timer.Timer がありますが、ここではシンプルなjava.util.Timerを紹介します。
Timerクラスを利用すると
- 一定時間後に、1回だけ別処理を呼び出す
- 一定時間後から、定期的に繰り返し別処理を呼び出す
といった処理が簡単に実現できます。
なお欠点としては、「別処理」の中から直接画面への描画を行ってはいけない事でしょうか。この辺りは、前回記事のマルチスレッドを用いた時間計測でも同じことが言えます。
【詳細】
別処理部分を作成する
Timerにより呼び出される別処理部分を作成します。別処理部分は無名関数にしても良いですし、別クラスにしても良いでしょう。
どちらの場合もTimerTaskクラスを利用し、run()メソッドに別処理として動作する部分を記述します。
無名関数として実装する例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
void setup() { //ここはメイン処理 … //別処理を無名関数として作成する TimerTask task = new TimerTask() { public void run() { println("ここは別処理です"); } }; //ここで別処理を呼び出し … } |
別クラスとして実装する例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
void setup() { //ここはメイン処理 … //別処理をインスタンス化 OtherRun otherRun = new OtherRun(); //ここで別処理を呼び出し … } //別処理を行うクラス class OtherRun extends TimerTask { @Override public void run() { println("ここは別処理です"); } } |
こんな感じになります。
別処理部分を呼び出す
TimerTaskクラスの別処理を呼び出すには、JavaのTimerクラスを利用します。
.
Timer timer = new Timer(String name);
timer:生成されたTimerインスタンス
name:生成するタイマー名
1 |
Timer timer = new Timer(); |
Timerインスタンスの作成は簡単ですね。
生成したTimerインスタンスを利用して、TimerTaskクラスを継承した別処理部分を呼び出します。別処理部分は、別スレッドで動作します。ですので別処理部分から直接画面へ描画を行うことはできない事に注意してください。
Timerクラスには、別処理部分を呼び出すための命令が2種類存在します。
- scheduleメソッド
- scheduleAtFixedRateメソッド
この2つの命令は、別処理部分が期待した時間内に処理を終えられなかったときに、動作が異なってきます。
scheduleメソッドの基本的な使い方
void timer.schedule( TimerTask task, long delay, long period);
void timer.schedule(TimerTask task, Date firstTime, long period);
timer:生成されたTimerインスタンス
task:TimerTaskクラスを継承した別処理
firstTime:別処理を呼び出す日時
delay:別処理を呼び出すまでの待ち時間(ms)
period:別処理を呼び出す間隔(ms)
指定日時になったら1回だけ呼び出すには、例えば以下のようにします。
1 2 3 4 5 6 7 8 9 10 11 12 |
try{ //文字列をDateに変換する String strDate = "2020/02/06 15:03:00"; SimpleDateFormat sdFormat = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss"); Date firstTime = sdFormat.parse(strDate); //別処理を呼び出す timer.schedule( otherRun,firstTime ); } catch( ParseException e ){ e.printStackTrace(); } |
上記例では文字列を日付型に変換し、指定日時になったら呼び出しを行っています。
もしもscheduleメソッドを実行した時間が指定日時に比べて過去になっている場合(例:15:00に別処理を起動するように指定したが、その時点で既に16:00だった場合など)は、直ちに呼び出しが行われます。
ただしこの方法では、呼び出しは1回しか行われない事に注意してください。
一定間隔で繰り返し呼び出すには、以下のようにします。
1 2 |
//一定間隔で、別処理を呼び出す timer.schedule( otherRun, 1000, 5000 ); |
上記例では、scheduleメソッドを実行した1秒後(1000ミリセカンド後)から5秒(5000ミリセカンド)間隔で、繰り返し別処理を呼び出します。
繰り返し呼び出す場合、もしも別処理側が指定時間(上記例なら5秒)以内に終わらなかった場合は、以下のようになります。
scheduleメソッドでは、1回でも処理遅延があると、その時間がどんどんと蓄積していく事になります。
ただし別処理側に遅延がなければ毎回periodミリ秒間隔で呼び出されるので、できるだけ一定間隔で処理を行いたい場合は、適した方法となります。
scheduleAtFixedRateメソッドの基本的な使い方
void timerscheduleAtFixedRate(TimerTask task, long delay, long period);
timer:生成されたTimerインスタンス
task:TimerTaskクラスを継承した別処理
firstTime:別処理を呼び出す日時
delay:別処理を呼び出すまでの待ち時間(ms)
period:別処理を呼び出す間隔(ms)
基本的な使い方はscheduleメソッドと同じです。
指定日時になったら呼び出すには、例えば以下のようにします。
1 2 3 4 5 6 7 8 9 10 11 12 |
try{ //文字列をDateに変換する String strDate = "2020/02/06 15:03:00"; SimpleDateFormat sdFormat = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss"); Date firstTime = sdFormat.parse(strDate); //別処理を呼び出す timer.scheduleAtFixedRate( otherRun,firstTime,5000 ); } catch( ParseException e ){ e.printStackTrace(); } |
上記例では文字列を日付型に変換し、指定日時になったら呼び出しを行っています。
もしもscheduleAtFixedRateメソッドを実行した時間が指定日時に比べて過去になっている場合(例:15:00に別処理を起動するように指定したが、その時点で既に16:00だった場合など)は、直ちに呼び出しが行われます。
scheduleメソッドと異なるのは、以降はperiodミリ秒間隔で(上記例では5000ミリ秒間隔で)、別処理が繰り返し呼び出される事です。
最初から一定間隔で繰り返し呼び出す場合には、以下のようにします。
1 2 |
//一定間隔で、別処理を呼び出す timer.scheduleAtFixedRate( otherRun,0, 5000 ); |
上記例では、scheduleAtFixedRateメソッドを実行した直後(0ミリセカンド後)から5秒(5000ミリセカンド)間隔で、繰り返し別処理を呼び出します。
もしも別処理側が指定時間(上記例なら5秒)以内に終わらなかった場合は、以下のようになります。
scheduleAtFixedRateでは、可能な限り予定通りに呼び出そうとします。つまり一定時間の範囲内で、すべての呼び出しを終えたい場合に有効です。
逆に言えば別処理側に遅延が多い場合は、呼び出し間隔がバラバラになるので、そこは注意してください。
参考とした記事:
@IT様 : Javaのタスクを定期的に実行する
呼び出しを止める
繰り返し呼び出すのを停止するには、Timerクラスのcancelメソッドを利用します。
.
timer:生成されたTimerインスタンス
使い方は簡単ですね。
cancelメソッドは、現在稼働中の別処理には影響を与えません。つまり実行中の別処理が即座に停止するわけではないという事です。
cancelメソッドが実行されると、次回から別処理が呼び出されることが無くなります。
なお、一旦キャンセルされたタイマーを再開する手段はありません。再開したい場合は、新しくscheduleまたはscheduleAtFixedRateメソッドを呼び出す必要があります。
【関連記事】
サンプルプログラム
一定時間後に繰り返し処理を行う例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
/** * PROCESSING 3 タイマーSample * @auther MSLABO * @version 2020/02 1.0 */ import java.util.TimerTask; import java.util.Timer; import java.text.SimpleDateFormat; import java.util.Date; SimpleDateFormat sdFormat = null; Timer timer = null; boolean runninngTimer = false; int count = 0; void setup() { //ここはメイン処理 timer = new Timer(); sdFormat = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss SSSS"); //ここで別処理を呼び出し //一定間隔で、別処理を呼び出す OtherRun otherRun = new OtherRun(); timer.schedule( otherRun, 1000, 5000 ); runninngTimer = true; } void draw(){ } //別処理を行うクラス class OtherRun extends TimerTask { @Override public void run() { //回数と現在時刻を表示 count++; println( nf(count,2) + ":" + sdFormat.format(new Date())); } } void mouseClicked(){ if( runninngTimer ){ //マウスクリックでタイマー停止 println("do cancel"); timer.cancel() ; } } |
実行すると5秒間隔でOtherRunクラスのrunメソッドを呼び出します。マウスクリックで、呼び出しを停止します。
<出力サンプル>
一定時間経過した事を検出する例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
/** * PROCESSING 3 タイマーSample2 * @auther MSLABO * @version 2020/02 1.0 */ import java.util.TimerTask; import java.util.Timer; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Calendar; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; SimpleDateFormat sdFormat = null; Timer timer = null; boolean timerFlg = false; OtherRun otherRun = null; /** * 現在時刻からn秒後を求める処理 * @param n秒 * @return n秒後のDate */ public Date addSecond(int addSecond){ // Date型の日時をCalendar型に変換 Calendar calendar = Calendar.getInstance(); calendar.setTime(new Date()); // 日時を加算する calendar.add(Calendar.SECOND, addSecond); // Calendar型の日時をDate型に戻す Date d = calendar.getTime(); return d; } void setup() { //日時表示用の書式設定 sdFormat = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss SSSS"); //タイマー生成 timer = new Timer(); //ここで別処理を生成 otherRun = new OtherRun(); } void draw(){ } void mouseClicked(){ //マウスクリックから3秒計測する if(timerFlg == false){ //サブスレッド実行 println( "3秒計測開始:" + sdFormat.format(new Date())); //現在から3秒後に別処理実行 timer.schedule( otherRun, addSecond( 3 ) ); } timerFlg = true; } //別処理を行うクラス class OtherRun extends TimerTask { @Override public void run() { //ここが3秒後に呼び出される timerFlg = false; println("3秒計測終了:" + sdFormat.format(new Date())); } } |
マウスをクリックすると、その時点から3秒経過したかどうかを計測し、メッセージを表示します。
<出力サンプル>
本ページで利用しているアイコン画像は、下記サイト様より拝借しております。各画像の著作権は、それぞれのサイト様および作者にあります。