【Java】TimerとTimeTaskの詳細

6620 ワード

以下の内容はThe JavaTM Tutorialと関連API docによって翻訳し整理して、後の参考にします。
1.概要
Timerは、バックグラウンドスレッドで指定されたタスクを実行するためのタイマーツールである。一つのタスクを一回または何回も実行する計画ができます。
TimerTaskは抽象的なクラスであり、そのサブクラスはTimerによって計画されるタスクを表す。
簡単なルーチン:
package test.util;

import java.util.Timer;
import java.util.TimerTask;

/**
 * Simple demo that uses java.util.Timer to schedule a task to execute once 5
 * seconds have passed.
 */


public class Reminder
{
	Timer timer;


	public Reminder(int seconds)
	{
		timer = new Timer();
		timer.schedule(new RemindTask(), seconds * 1000);
	}


	class RemindTask extends TimerTask
	{
		public void run()
		{
			System.out.println("Time's up!");
			timer.cancel(); // Terminate the timer thread
		}
	}


	public static void main(String args[])
	{
		System.out.println("About to schedule task.");
		new Reminder(5);
		System.out.println("Task scheduled.");
	}
}
はこの小さい例を実行して、まず見ます。
About to schedule task.
5秒後に見られます。
Time's up
この小さな例は、いくつかのTimerスレッドを用いて実装され計画されたタスクを実行するための基礎ステップを説明することができる。
(1)カスタムTimerTaskを実現するサブクラス、runメソッドは実行するタスクコードを含み、この例ではこのサブクラスはRemindTaskである。
(2)Timerクラスを実装し、タイマーバックグラウンドスレッドを作成します。
(3)タスクオブジェクトの実装(new RemindTask() 
(4)実行計画を立てる。ここではschedule法を用いて、最初のパラメータはTimeTaskオブジェクトであり、第二のパラメータは実行開始前の遅延時間を表している(単位はmilisecondsであり、ここで5000を定義している)。
もう一つの方法はタスクの実行時間を指定できます。例えば、11:01 p.m.でタスクを指定します。
//Get the Date corresponding to 11:01:00 pm today.
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 23);
calendar.set(Calendar.MINUTE, 1);
calendar.set(Calendar.SECOND, 0);
Date time = calendar.getTime();
timer = new Timer();
timer.schedule(new RemindTask(), time); 
2.Timerスレッドの終了
デフォルトでは、プログラムのtimerスレッドが実行されている限り、このプログラムは実行され続けます。もちろん、以下の4つの方法でtimerスレッドを終了できます。
(1)timerのcancleメソッドを呼び出します。この方法は、プログラムのどこからでも呼び出すことができます。また、ティメラtaskのrunメソッドにもあります。
(2)timerスレッドをdaemenスレッドにします。これはプログラムがdaemenスレッドのみの場合、自動的に実行を終了します。 
(3)timer関連のすべてのtaskが実行されたら、このtimerオブジェクトの参照をすべて削除します。これでtimerスレッドも終了します。 
(4)System.exitメソッドを呼び出して、プログラム全体(全スレッド)を終了させます。 
Reminderの例は第一の方式を使用した。ここでは第二の方式は使えません。ここではプログラムをtimerのタスク実行まで実行する必要がありますので、daemenを設定すると、mainスレッドが終了すると、プログラムはtimerというdaemenスレッドだけが残ります。したがって、プログラムはtimerスレッドの実行を待つことなく終了します。
一部の場合、プログラムの終了はtimerスレッドだけではありません。例えば、AWTを使ってbeepに来たら、AWTは自動的に非daemenスレッドを作成してプログラムの実行を維持します。以下のコードはReminderを修正しました。beeping機能を追加しました。System.exitの呼び出しに参加してプログラムを終了します。
package test.util;

import java.util.Timer;
import java.util.TimerTask;
import java.awt.Toolkit;
/**
 * Simple demo that uses java.util.Timer to schedule a task to execute once 5
 * seconds have passed.
 */
public class ReminderBeep
{
	Toolkit toolkit;
	Timer timer;


	public ReminderBeep(int seconds)
	{
		toolkit = Toolkit.getDefaultToolkit();
		timer = new Timer();
		timer.schedule(new RemindTask(), seconds * 1000);
	}


	class RemindTask extends TimerTask
	{
		public void run()
		{
			System.out.println("Time's up!");
			toolkit.beep();
			//timer.cancel(); //Not necessary because we call System.exit
			System.exit(0); // Stops the AWT thread (and everything else)
		}
	}


	public static void main(String args[])
	{
		System.out.println("About to schedule task.");
		new ReminderBeep(5);
		System.out.println("Task scheduled.");
	}
}
3.一つのタスクを繰り返し実行する
まず例を見ます。
package test.util;


import java.awt.Toolkit;
import java.util.Timer;
import java.util.TimerTask;


public class AnnoyingBeep {
    Toolkit toolkit;
    Timer timer;


    public AnnoyingBeep() {
        toolkit = Toolkit.getDefaultToolkit();
        timer = new Timer();
        timer.schedule(new RemindTask(),0,1*1000);  //subsequent rate
    }


    class RemindTask extends TimerTask {
        int numWarningBeeps = 3;


        public void run() {
            if (numWarningBeeps > 0) {
                toolkit.beep();
                System.out.println("Beep!");
                numWarningBeeps--;
            } else {
                toolkit.beep(); 
                System.out.println("Time's up!");
                //timer.cancel(); //Not necessary because we call System.exit
                System.exit(0);   //Stops the AWT thread (and everything else)
            }
        }
    }
    
	public static void main(String args[])
	{
		System.out.println("About to schedule task.");
		new AnnoyingBeep();
		System.out.println("Task scheduled.");
	}
}
実行します。次のような出力が見られます。Task scheduled。
Beep     
Beep     //one second after the first beep
Beep     //one second after the second beep
Time's up!//one second after the third beep
ここでは3つのパラメータのschedule法を用いて,taskを1秒ごとに実行するよう指定した。以下のように全てのTimer類を用いて計画を立ててtaskを繰り返し実行する方法を示します。 
schedule(TimeTask task,long delay,long period) 
schedule(TimeTask task,Date time,long period) 
scheduleAt FixedRate(TimeTask task、long delay、long period) 
scheduleAt FixedRate(TimeTask task,Date firstTime,long period) 
繰り返し実行するタスクを計画する時、もしタスクの滑らかさを重視するなら、schedule方法を使ってください。気になるのがタスクの実行頻度なら、scheduleAtFixedRate方法を使います。例えば、ここでschedule方法を使用して、これは全てのbeepの間の時間間隔が少なくとも1秒であることを意味しています。つまり、何らかの理由でbeapが遅れた場合(計画通りに実行されていません)、残りのbeepはすべて遅延して実行されます。このプログラムをちょうど3秒後に終了させたいなら、どのbeepがどんな理由で遅延されても、scheduleAtFixedRate方法を使用して、最初のbeepが遅れると、一番速いスピードで後ろのbeepが緊密に実行されます。
4.scheduleとscheduleAt FixedRateをさらに分析する。
(1)2つのパラメータのscheduleがタスクプランを作成する時、指定された計画実行時間scheduledExecution Time<=system CurrenntTime、taskは直ちに実行されます。scheduledExecutionTimeは、あるtaskの過剰な実行によっては変更されません。(2)3つのパラメータのscheduleは、一つのtaskを繰り返し実行する計画を立てる時、このtaskを実行する計画実行時間は前回の実際実行時間とともに変化します。つまり、scheduledExectionTime(n+1回目)=realExecution Time(n回目)+periodTime。つまり、taskをn回目に実行した場合、何らかの理由で今回の実行時間が長すぎて、実行後のsystem CurrenntTime==scheduledExecution Time(n+1回目)を実行した場合は、その時点で待つことなく、n+1回目のtaskを実行し、次のn+2回目のscheduledExectionTime+2回目のExectime(n+1回目のExectime+1回目のExectime)となります。はっきり言って、この方法は間隔を置く時間の安定をもっと重視します。
(3)3つのパラメータのscheduleAtFixedRateは、一つのtaskを繰り返し実行する計画を制定する時、一回ごとにこのtaskを実行する計画実行時間は最初に決められました。つまり、scheduledExecutionTime(n回目)=first ExecuteTime+n*periodTimeです。taskをn回目に実行した場合、何らかの理由で今回の実行時間が長すぎて、実行後のsystem CurrenntTime==scheduledExecution Time(n+1回目)を実行した場合は、period間隔を設けずにn+1回目のtaskを実行し、次のn+2回目のtaskのscheduledExectionTimeは依然としてExectime+2回目である。(n+2)*periodTimeは初めてtaskを実行すると決められました。つまり、この方法は実行周波数の安定を保つことにより重視されます。
5.いくつかの注意事項
各Timerは、唯一のスレッドにのみ対応している。
Timerは任務の実行が非常に正確であることを保証しない。
Timer類のスレッドは安全です。
転載元:http://blog.csdn.net/siyue_qi/article/details/2469316