はじめに (対象読者・この記事でわかること)

この記事は、Javaの基本的な文法を理解している方、プログラミング初〜中級者を対象にしています。特に、Javaで時間を扱う処理や非同期処理に興味がある方に最適です。

この記事を読むことで、Javaで一定時間経過後に文字列をコンソールに出力する3つの方法(Thread、Timer、ScheduledExecutorService)の実装方法を習得できます。各方法の特徴と使い分け方も理解できるため、実際の開発現場で適切なタイマー処理を選択できるようになります。

前提知識

この記事を読み進める上で、以下の知識があるとスムーズです。 - Javaの基本的な文法 - クラスとオブジェクトの概念 - メソッドの定義と呼び出し - コンソール出力(System.out.println)の基本的な使い方

Javaで遅延実行を実現する必要性

Javaアプリケーション開発において、一定時間経過後に特定の処理を実行する必要がある場面は多々あります。例えば、ユーザー操作後の遅延処理、定期実行タスクの遅延開始、バッチ処理の遅延実行などが挙げられます。

Javaにはこのような遅延実現をサポートする複数の方法が存在します。それぞれの方法には特徴や適した使用場面があるため、状況に応じて適切な方法を選択することが重要です。この記事では、代表的な3つの方法(Thread、Timer、ScheduledExecutorService)を具体的なコード例と共に解説します。

具体的な実装方法

ステップ1: Threadとsleepメソッドを使った方法

最も基本的な遅延実行の方法は、Threadクラスのsleepメソッドを使用することです。この方法はシンプルで理解しやすいですが、注意点もあります。

Java
public class DelayPrintWithThread { public static void main(String[] args) { System.out.println("処理開始: " + System.currentTimeMillis()); // 別スレッドで遅延実行 new Thread(() -> { try { // 3秒待機 Thread.sleep(3000); System.out.println("3秒後に表示: " + System.currentTimeMillis()); } catch (InterruptedException e) { System.err.println("スレッドが割り込まれました"); Thread.currentThread().interrupt(); } }).start(); System.out.println("メインスレッドは続行します"); } }

この方法の特徴: - 別スレッドで処理を実行するため、メインの処理に影響を与えない - try-catchでInterruptedExceptionを処理する必要がある - 単純な遅延実現に適している

ステップ2: TimerとTimerTaskを使った方法

Java標準ライブラリのTimerクラスとTimerTaskクラスを使用すると、より高機能なタイマー処理を実装できます。

Java
import java.util.Timer; import java.util.TimerTask; public class DelayPrintWithTimer { public static void main(String[] args) { System.out.println("処理開始: " + System.currentTimeMillis()); // Timerの作成 Timer timer = new Timer(); // TimerTaskの作成 TimerTask task = new TimerTask() { @Override public void run() { System.out.println("3秒後に表示: " + System.currentTimeMillis()); timer.cancel(); // タイマーの終了 } }; // 3秒後にタスクを実行 timer.schedule(task, 3000); System.out.println("メイン処理は続行します"); } }

この方法の特徴: - Timerクラスがスレッドを管理してくれる - scheduleメソッドで遅延時間と実行間隔を指定できる - タスクのキャンセルが容易 - 複数のタスクを管理できる

ステップ3: ScheduledExecutorServiceを使った方法

Java 5で導入されたScheduledExecutorServiceは、より現代的で柔軟なスケジューリングを提供します。

Java
import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class DelayPrintWithScheduledExecutor { public static void main(String[] args) { System.out.println("処理開始: " + System.currentTimeMillis()); // スレッドプールの作成 ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); // 遅延実行タスクの登録 scheduler.schedule(() -> { System.out.println("3秒後に表示: " + System.currentTimeMillis()); }, 3, TimeUnit.SECONDS); // スケジューラのシャットダウン(実際のアプリケーションでは適切なタイミングで実行) // scheduler.shutdown(); System.out.println("メイン処理は続行します"); } }

この方法の特徴: - スレッドプールを利用してリソースを効率的に管理 - 固定遅延や固定レートでの繰り返し実行が可能 - 例外処理が容易 - アプリケーション全体のライフサイクルと統合しやすい

ハマった点やエラー解決

スレッドの割り込み処理

Thread.sleep()を使用する場合、割り込みが発生するとInterruptedExceptionがスローされます。これを適切に処理しないと、アプリケーションが不安定になる可能性があります。

問題コード:

Java
try { Thread.sleep(3000); } catch (InterruptedException e) { // 何もしない }

解決策:

Java
try { Thread.sleep(3000); } catch (InterruptedException e) { System.err.println("スレッドが割り込まれました"); Thread.currentThread().interrupt(); // 割り込みフラグを再設定 }

Timerのキャンセル忘れ

Timerを使用する際、アプリケーション終了前にTimerをキャンセルしないと、デーモンスレッドとして実行され続ける可能性があります。

解決策:

Java
// アプリケーション終了前に必ず呼び出す timer.cancel();

ScheduledExecutorServiceのシャットダウン

ScheduledExecutorServiceは、シャットダウンしないとJVMが終了しなくなることがあります。

解決策:

Java
// アプリケーション終了前に必ず呼び出す scheduler.shutdown();

まとめ

本記事では、Javaで一定時間経過後に文字列を出力する3つの方法を解説しました。

  • Threadとsleepメソッド: シンプルで基本的な遅延実現に適していますが、手動でスレッド管理が必要です。
  • TimerとTimerTask: 標準ライブラリで提供されるタイマー機能で、複数のタスク管理が容易です。
  • ScheduledExecutorService: 現代的で柔軟なスケジューリングが可能で、スレッドプールを効率的に利用できます。

この記事を通して、Javaで遅延実行を実現する方法を理解し、状況に応じた適切なタイマー処理を選択できるようになったことでしょう。

今後は、これらのタイマー処理を応用した、より複雑なスケジューリングや非同期処理についても記事にする予定です。

参考資料