アプレットの表示を動かす

 アプレットの典型例としてしばしば紹介されるのが、アニメーションの機能です。 WWWのページ上でマスコットのイメージが動き回ったり、 「電光掲示版」や「時計」のような機能を実現することもできます。 効果的に用いれば従来のハイパーテキストに比べ、 格段にバラエティーに富んだページを作ることが可能でしょう。 それらの機能を実現するために「スレッド」と呼ばれる仕組みを利用します。


5-1 スレッドの処理を組み込む

スレッド(Thread)とは?

 最初に「スレッド」について簡単に解説しておきましょう。 「スレッド」という用語は Java言語だけのものではありません。 最近の OS の基本概念の1つです。 簡単に説明すると、1つのプログラムをさらに細かい仕事の単位に分けたものです。 複数のスレッドによって処理の並列化を上手に実現すると、 プログラムの実行効率を上げることが可能になります。 既に紹介した例では、 ネットワークを通じて画像データを読んでいる間に他の処理を進めました。 ユーザーの入力を待つ間に、他の処理を行うなどの工夫も考えられます。 スレッドの導入は、 プログラムを設計する上でも大きな手助けになります。 とりわけマルチメディアを扱うアプリケーションの場合、 単独のプログラムで複数の入出力を同時に処理しなくてはいけません。 開発言語がスレッドへのインターフェイスをサポートしてくれれば、 こうしたのプログラムを自然な形で実現することができます。 アニメーションをしながら音楽を流すというようなプログラミングは容易です。

 Java言語には Thread(スレッド)と呼ばれるクラスが用意されています。 Java言語は OS に非依存です。したがって Threadクラスは、 OSレベルの「スレッド」そのものではありません。 むしろ、 「スレッド(もしくはそれを疑似的に提供できる仕組み) とのインターフェイスを実現するクラス」だと考えてください。 またアプレットのプログラムの表面に Threadクラスのオブジェクトが現れなくても、 実行時には多くのスレッドが存在するのが普通です。 画像データの読み込みや音声データの出力は、 常に独立したスレッドで処理されます。 Java言語のプログラミングでは、この「並列性」を理解しておかないと 混乱が生じるケースもでてきます。 その対策についてはこの章の後の節で触れます。


5-1-2 スレッドの使い方


implements とインターフェイス

 アプレットの中でスレッドを利用する方法を具体的に説明しましょう。 アプレットがスレッドを利用するためには、 クラスを設計するための新しい手段である implements が必要です。 今までのイベント処理など機能は、 全て Appletクラスにあらかじめ用意されていました。 ところが Threadクラスを取り扱う機能は、 Appletクラス自身にはありません。
 このような場合 Java言語では、 クラス定義の最初の行でキーワード implements を用います。 implements は、 ベースとなるクラスの中には存在しない別の機能を追加する命令です。 implements の後に指定されるデータは、「インターフェイス」と呼ばれる特殊なクラスです。 スレッドを扱うためには Runnable というインターフェイスが利用されます。 実際のクラス定義の例で見てみましょう。


public class Clock extends Applet implements Runnable {
                      :
                      :

 上の例では新しいクラス Clock は、Applet というクラスと、 Runnable というインターフェイスの両方から機能を受け継ぐことになります。

Runnable と Thread

 実は Runnableの内部にあるのは、 run() という名前のメソッドのみです。 しかも Runnableはインターフェイスですから、このメソッドには中身はありません。 (これから作成する新しいアプレットの中で再定義を必要とします。) メソッド run() はスレッドが実行すべき処理の内容を与えます。 (正確に言うと与える予定になっている。) Runnable によって追加されるのは、 Threadクラスのオブジェクトではないことに注意してください。 ですから、アプレットの中では Threadのオブジェクトを 最低1つ(たいていは1つ)新しく用意します。


public class Clock extends Applet implements Runnable {

       public Thread clock = null;  // スレッドの宣言
                      :
                      :

Threadクラスのオブジェクトをコンストラクタによって生成する場合、 引数として run() メソッドを内部にインプリメントされた オブジェクト(すなわちアプレット自身)を与える必要があります。 この仕事はアプレットの start() メソッド か mouseDonw() メソッドの中で行うのが適当でしょう。


       clock = new Thread( this );

これでスレッドと、 アプレットで定義された run()メソッドの処理とが結びつけられたことになります。 これ以降のスレッドの処理のコントロールは、 すべて Threadクラスのオブジェクト(上の例では clock )を 通じて行われます。

スレッドを使ったアプレットの実例

 簡単な例で見てみましょう。 「デジタル時計」のアプレット です。 このプログラムでは、新しく Dateというクラスが利用されています。 このクラスは java.util パッケージに含まれます。 Date はシステムから日付と時刻の情報を受け取るためのクラスです。 Threadクラスもそうでしたが、 Java言語ではシステムとのインターフェイスもすべてクラスの 概念を通じて行うわけです。 Date クラスのオブジェクトは、コンストラクタに引数を与えないで 生成すると、その瞬間の日付と時刻が内部に記憶されます。 その情報は、 toString() メソッドを用いれば Stringクラスのデータに変換された形で 得ることができます。 プログラマーから見た取り扱いは、他のクラスと全く同じであることが わかるでしょう。 また OSに依存する部分は、このクラスの内部に完全に隠されています。

スレッドのコントロール

 Runnable から受け継いだ run() の他に、 スレッドのコントロールと関係が深いアプレットのメソッドに、 次のものがあります。

スレッドに関連するアプレットのメソッド
メソッド名 機能
start() アプレットがページに現れた時に呼ばれる処理
stop() アプレットがページから消えた時に呼ばれる処理
run() スレッドとして実行する処理

start() はページに現れた時に自動的に呼び出されます。 init() がアプレットを初期化する時に一度だけ呼ばれるのと違って、 start()はページの移動やスクローリングで現れるたびに呼び出されます。 逆にアプレットがページから消える時に stop() が呼ばれます。 stop()も何度か呼び出される可能性があります。ただし、 もう二度とアプレットのあるページに帰ってこない場合もあるわけですから、 このメソッドの中に後始末の処理をきちんと用意してください。

スレッドをコントロールするためのThreadのメソッドには、 次のようなものがあります。

Threadの主なメソッド
メソッド名 機能
start() スレッドの処理を開始させる
stop() スレッドの処理を停止させる
isAlive() スレッドが活動中か判定する
sleep() 現在のスレッドの処理を一時的に停止させる
引数は休憩する時間(ミリ秒単位)

これらのメソッドの使用法は、半ばパターン化されています。 Threadクラスの start()は、アプレットの start() メソッドか マウスのイベント処理のメソッドの中で呼び出します。 アプレットの start() メソッドから呼び出せば、 ページに登場した時からスレッドの処理が始まります。 たとえばアニメーションを最初から動かしたり、 上のサンプルの時計のような場合は、このパターンになります。 もし時計ではなく「ストップ・ウォッチ」であれば、 mouseDown() のメソッドの中でスレッドを起動した方がいいでしょう。 Threadクラスの stop() も同様で、 アプレットの stop()メソッドか マウスのイベント処理のメソッドの中から呼び出します。 Threadクラスの sleep() メソッドは、run()メソッドの中で呼び出すのが普通です。 また Thread のオブジェクトを完全に消滅させたい時は、 他のクラスのオブジェクト同様、値に null を代入します。