Javaタイマー

Javaタイマー

1. タイマー–基本

TimerおよびTimerTaskは、バックグラウンドスレッドでタスクをスケジュールするために使用されるjavautilクラスです。 一言で言えば–TimerTask is the task to perform and Timer is the scheduler

2. タスクを1回スケジュールする

Timerを使用して、単純にrunning a single taskから始めましょう。

@Test
public void givenUsingTimer_whenSchedulingTaskOnce_thenCorrect() {
    TimerTask task = new TimerTask() {
        public void run() {
            System.out.println("Task performed on: " + new Date() + "n" +
              "Thread's name: " + Thread.currentThread().getName());
        }
    };
    Timer timer = new Timer("Timer");

    long delay = 1000L;
    timer.schedule(task, delay);
}

これを実行しているのがJUnitテストである場合は、Thread.sleep(delay * 2)呼び出しを追加して、JUnitテストの実行が停止する前にタイマーのスレッドがタスクを実行できるようにする必要があることに注意してください。

3. 繰り返しタスクを一定の間隔でスケジュールする

次へ–schedule a task to run at a pre-defined intervalをしましょう。

scheduleAtFixedRate(repeatedTask, delay, period) APIを利用します。これは、指定された遅延の後に開始して、固定レートの繰り返し実行のためにタスクをスケジュールします。 後続の実行は、指定された期間で区切られた定期的な間隔で行われます。

@Test
public void givenUsingTimer_whenSchedulingRepeatedTask_thenCorrect(){
    TimerTask repeatedTask = new TimerTask() {
        public void run() {
            System.out.println("Task performed on " + new Date());
        }
    };
    Timer timer = new Timer("Timer");

    long delay  = 1000L;
    long period = 1000L;
    timer.scheduleAtFixedRate(repeatedTask, delay, period);
}

注意–何らかの理由(ガベージコレクションやその他のバックグラウンドアクティビティなど)で実行が遅れると、2つ以上の実行が連続して発生し、「追いつく」ことになります。

3.1. 毎日のタスクをスケジュールする

次へ–run a task once a day

@Test
public void givenUsingTimer_whenSchedulingDailyTask_thenCorrect() {
    TimerTask repeatedTask = new TimerTask() {
        public void run() {
            System.out.println("Task performed on " + new Date());
        }
    };
    Timer timer = new Timer("Timer");

    long delay = 1000L;
    long period = 1000L * 60L * 60L * 24L;
    timer.scheduleAtFixedRate(repeatedTask, delay, period);
}

4. TimerTimerTaskをキャンセルします

タスクの実行は、いくつかの方法でキャンセルできます。

4.1. Run内のTimerTaskをキャンセルします

TimerTask自体のrun()メソッドの実装内でTimerTask.cancel()メソッドを呼び出すと、次のようになります。

@Test
public void givenUsingTimer_whenCancelingTimerTask_thenCorrect()
  throws InterruptedException {
    TimerTask task = new TimerTask() {
        public void run() {
            System.out.println("Task performed on " + new Date());
            cancel();
        }
    };
    Timer timer = new Timer("Timer");

    timer.scheduleAtFixedRate(task, 1000L, 1000L);

    Thread.sleep(1000L * 2);
}

4.2. Timerをキャンセルします

TimerオブジェクトでTimer.cancel()メソッドを呼び出すと、次のようになります。

@Test
public void givenUsingTimer_whenCancelingTimer_thenCorrect()
  throws InterruptedException {
    TimerTask task = new TimerTask() {
        public void run() {
            System.out.println("Task performed on " + new Date());
        }
    };
    Timer timer = new Timer("Timer");

    timer.scheduleAtFixedRate(task, 1000L, 1000L);

    Thread.sleep(1000L * 2);
    timer.cancel();
}

4.3. Run内のTimerTaskのスレッドを停止します

タスクのrunメソッド内でスレッドを停止して、タスク全体をキャンセルすることもできます。

@Test
public void givenUsingTimer_whenStoppingThread_thenTimerTaskIsCancelled()
  throws InterruptedException {
    TimerTask task = new TimerTask() {
        public void run() {
            System.out.println("Task performed on " + new Date());
            // TODO: stop the thread here
        }
    };
    Timer timer = new Timer("Timer");

    timer.scheduleAtFixedRate(task, 1000L, 1000L);

    Thread.sleep(1000L * 2);
}

run実装のTODO命令に注意してください。この簡単な例を実行するには、実際にスレッドを停止する必要があります。

実際のカスタムスレッドの実装では、スレッドの停止をサポートする必要がありますが、この場合、非推奨を無視して、Threadクラス自体で単純なstopAPIを使用できます。

5. Timer VSExecutorService

タイマーを使用する代わりに、ExecutorServiceを活用してタイマータスクをスケジュールすることもできます。

指定した間隔で繰り返しタスクを実行する方法の簡単な例を次に示します。

@Test
public void givenUsingExecutorService_whenSchedulingRepeatedTask_thenCorrect()
  throws InterruptedException {
    TimerTask repeatedTask = new TimerTask() {
        public void run() {
            System.out.println("Task performed on " + new Date());
        }
    };
    ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
    long delay  = 1000L;
    long period = 1000L;
    executor.scheduleAtFixedRate(repeatedTask, delay, period, TimeUnit.MILLISECONDS);
    Thread.sleep(delay + period * 3);
    executor.shutdown();
}

では、TimerソリューションとExecutorServiceソリューションの主な違いは何ですか?

  • Timerは、システムクロックの変化に敏感である可能性があります。 ScheduledThreadPoolExecutor

  • Timerには実行スレッドが1つだけあります。 ScheduledThreadPoolExecutorは、任意の数のスレッドで構成できます

  • TimerTask内でスローされたランタイム例外はスレッドを強制終了するため、次のスケジュールされたタスクはそれ以上実行されません。 withScheduledThreadExecutor –現在のタスクはキャンセルされますが、残りは引き続き実行されます

6. 結論

このチュートリアルでは、Javaに組み込まれているシンプルでありながら柔軟なTimerおよびTimerTaskインフラストラクチャを利用して、タスクをすばやくスケジュールするためのさまざまな方法を説明しました。 もちろん、Javaの世界には、必要に応じて、the Quartz libraryなど、はるかに複雑で完全なソリューションがありますが、ここから始めるのが非常に適しています。

これらの例の実装はthe github projectにあります。これはEclipseベースのプロジェクトであるため、そのままインポートして実行するのは簡単です。