SHOEISHA iD

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

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

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

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

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

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

synchronizedについて

 さてrunメソッドの中で、もうひとつ注目してほしい点があります。スレッド内で実行しているsetTimeメソッドです。ここではsynchronizedというものがつけられていますね。 これは一体、何でしょうか?

 これは、多重アクセスを防ぐためのものです。新しいスレッドを作って実行する場合、あるオブジェクトが、複数のスレッドから同時にアクセスされる可能性に注意しなければなりません。

 例えば、ファイルの読み書きなどを処理をスレッドで実行させたとしましょう。さて、あるスレッドからファイルを読み込んでいる最中に、別のスレッドからファイルを書き換えてしまったらどうなるでしょうか。とりあえず、とんでもないトラブルを引き起こしてしまいそうですよね。

 そこで、この部分を実行している間は、他のスレッドからオブジェクトにアクセスできないようにするために用意されているのが、synchronizedです。これをつけたメソッドの実行中は、他のスレッドからそのオブジェクトへアクセスできなくなります。

 まぁ、このサンプルでは単に新スレッドからLabelの表示テキストを変更しているだけですので、synchronizedなど使わなくとも問題が起こることはまずないんですが、synchronizedはこんな具合に使うのだな、というひとつの利用例として見てください。

Runnableによるスレッド処理の実装

 ここまでは、Threadクラスの継承によってスレッド処理を実現するパターンについて見てきました。ここからは、スレッドを実装するもう一つのやり方である「Runnableインターフェイスを利用するパターン」について見ていきましょう。まずは、先ほどのサンプルコードを修正します。

Runnableによるスレッド処理の実装
/* import宣言は省略 */

class TimeLabel extends JLabel implements Runnable {
    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 Thread(this);
        thread.start();
    }
    
    public synchronized void setTime(){
        Calendar calendar = Calendar.getInstance(Locale.JAPAN);
        this.setText(format.format(calendar.getTime()));
    }

    public void run() {
        while(roop_flag){
            try {
                Thread.sleep(1000);
            } catch(InterruptedException e){
                e.printStackTrace();
            }
            setTime();
        }
    }
}

 この例では、Threadのサブクラスはありません。代わりに、TimeLabelクラスの宣言にimplements Runnableが追加されています。このRunnableインターフェイスを組み込むことで、このTimeLabelクラスはThreadのサブクラスと同様、新しいスレッド内で実行できるようになります。

 implements Runnableしたクラスでは、Threadのサブクラスと同じくrunメソッドを用意し、スレッドで実行する処理を記述します。このあたりは、Threadを継承するパターンと全く同じです。違うのは、スレッドの開始の仕方です。

Runnableをimplementsした場合のスレッド開始方法
Thread thread = new Thread(this);
thread.start();

 コンストラクタでは、まずnew Threadでスレッドを作成しています。この時、引数にRunnableimplementsしたクラスのインスタンスを渡します。これはインスタンスを新しいスレッドで実行しますよ、という指定です。生成したThreadstartメソッドを呼び出すと、新しいスレッドが開始されます。

 Runnableimplementsしたクラスでは、runというメソッドを必ず用意する必要があります。startすると、引数に指定されたインスタンス内のrunメソッドが新しいスレッド内で実行されます。

 ここまで2種類のスレッドの使用方法を説明しましたが、どちらを使うべき、という決まりがあるわけではありません。ただし、一般にSwing関係のアプリケーションというのは、何らかのGUI関係のクラスを継承して作成されているものです。従って、Thread継承クラスを作成するよりは、Runnableをimplementsする方法が一般的に用いられます。

 実をいえば、Threadというクラスの中身は、「Runnableをimplements済みのクラス」なのです。従って、どちらも中身は全く同じことをしているのですが、不必要にThreadクラスのサブクラスを作るよりは、Runnableをimplementsして実装するほうがよいでしょう。Threadを継承する方法は、runメソッドの他にもいろいろと用意する必要があるなど、特別な場合に用いる、と考えてください。

次のページ
SwingUtilitiesの利用

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

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

もっと読む

この記事の著者

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

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

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

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

この記事をシェア

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

イベント

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

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

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

メールバックナンバー