SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

作って覚えるJavaプログラミングのススメ

Java入門 (9) - タイマーとスレッド

作って覚えるJavaプログラミングのススメ 第9回

新しいスレッドで実行させる

 では、先ほどのサンプルをタイマーではなく、スレッドを利用した形に修正してみましょう。TimeLabelクラスを修正してみることにします。

著者注
 Swingコンポーネントを別スレッドで実行する場合には、ここでのスレッドの説明とは別に、ちょっとした注意が必要です。これについては後述します。
新しいスレッドでの実行
/* import宣言は省略 */

class TimeLabel extends JLabel {
    private static final long serialVersionUID = 1L;
    private DateFormat format;
    private boolean roop_flag;
    
    public TimeLabel(){
        this.setFont(new Font("Dialog",Font.BOLD,24));
        format = new SimpleDateFormat("HH:mm:ss");
        roop_flag = true;
        Thread thread = new TimerThread();
        thread.start();
    }
    
    public synchronized void setTime(){
        Calendar calendar = Calendar.getInstance(Locale.JAPAN);
        this.setText(format.format(calendar.getTime()));
    }
    
    class TimerThread extends Thread {
        
        public void run() {
            int n = 0;
            while(roop_flag){
                try {
                    Thread.sleep(1000);
                } catch(InterruptedException e){
                    e.printStackTrace();
                }
                System.out.println(n++);
                setTime();
            }
        }
    }
}

 こんな感じになりました。ここでは、TimeLabel内にTimerThreadというスレッド実行のためのクラスを用意し、TimeLabelの表示更新を行っています。

スレッド実行の仕組み

 このようにスレッドは、目的の処理を実装したオブジェクトを実行する形で処理を行いますが、そのオブジェクトの定義方法は大きく分けて2種類あります。一つは、今あげた例のようにThreadクラスを継承して新しいクラスを定義する方法。もう一つは、Runnableというインターフェイスをimplementsする(これは、この後で説明します)という方法です。これ以外のクラスは、スレッドとして実行することができません。

 Threadのサブクラスは、インスタンスを作成し、開始用のメソッドstartを呼び出すことで、そのインスタンスに用意してある処理を、新しいスレッドで実行することができます。ここではTimeLabel内にTimerThreadというクラスを用意しました。コンストラクタ部分を見てください。TimerThreadインスタンスを作成後、startというメソッドが呼び出されていますね。これが、新しいスレッドで処理を開始するためのメソッドです。

Threadのサブクラスのコンストラクタ
Thread thread = new TimerThread();
thread.start();

 ところで、TimerThreadにあるどのメソッドでも新スレッドで実行できるというわけではありません。新スレッドで実行する処理はすべてrunメソッドの内部に記載する必要があります。Threadのサブクラスには、このrunメソッドを必ず用意する必要があります。

 今回のサンプルコードでは、runメソッドでどのような処理を行っているのでしょうか。タイマーの場合のコードとは違って、単にsetTimeを呼び出すだけではなさそうです。

runメソッドの中身
public void run() {
    int n = 0;
    while(roop_flag){
        try {
            Thread.sleep(1000);
        } catch(InterruptedException e){
            e.printStackTrace();
        }
        System.out.println(n++);
        setTime();
    }
}

ループとsleepメソッド

 まず注目してほしいのはwhile(roop_flag)の部分です。runメソッド内の処理は無限ループの中に書かれています。先ほど説明したタイマーでは1回のタスクが完了した後も、一定間隔で繰り返し呼び出される仕組みとなっていました。

 一方、Threadrunメソッドは1回きりしか呼び出されません。そしてスレッドはrunメソッドの実行が終われば消滅してしまいます。もう一度処理を呼び出すためには、新しいThreadインスタンスを作成し、startしなければならないのです。

 そこで、定期的に繰り返して処理を行わせたい場合は、ループを使ってメソッドの終了とスレッドの消滅を回避します。サンプルでは特に想定していませんが、特定の条件でスレッドを終了させたい場合はroop_flagの値をfalseに変更します。ループを抜けるとrunメソッドの処理が完了し、スレッドは終了します。考え方としては非常に単純な仕組みです。

 ただし、そのままでは問題があります。ただループ内で処理を実行してしまうと、猛烈な勢いで処理を繰り返し続けることになってしまいます。いくら別スレッドとはいえ、これではCPUのパワーを無駄に消費してしまいます。タイマーのような定期的な処理を行いたい場合は、一定時間の待機を行う必要があります。

 サンプルコードで一定時間の待機を行っているのが、try内に記載されたThread.sleepです。Threadクラスのsleepメソッドは、引数に指定したミリ秒数だけ現在のスレッドの処理を一時停止します。今回は、1秒停止してからsetTimeを呼び出すようにしています。なお、このsleepメソッドはInterruptedExceptionという例外を発生させる場合があるので、例外処理を忘れないようにしてください。

次のページ
synchronizedについて

この記事は参考になりましたか?

作って覚えるJavaプログラミングのススメ連載記事一覧

もっと読む

この記事の著者

掌田 津耶乃(ショウダ ツヤノ)

三文ライター&三流プログラマ。主にビギナーに向けたプログラミング関連の執筆を中心に活動している。※現在、入門ドキュメントサイト「libro」、カード型学習サイト「CARD.tuyano.com」を公開...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/2597 2008/06/24 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー