
これまでのプログラムは、main()メソッドから始まって、順番に文を実行、条件判断文をたどっていました。
Javaでは、この「処理の流れ」を複数もつことができます。
コード上から複数の処理が同時に行われるしくみを持たせることができます。
この処理の流れをスレッド(thread)とよびます。
長い繰り返し文を使う処理が行われている間に、別のスレッドで他の処理を行うことができます。
スレッドを起動する
スレッドを起動するためには、Threadクラスを拡張したクラスを作成することが必要です。
Threadクラスを拡張したクラスには、run()メソッドを定義することが必要です。この処理が、これまでとは異なる処理の流れのスタート地点になるのです。
下記のコードでスレッドの様子をみましょう。


処理は、main()メソッドから始まります。
Threadクラスを拡張したクラスのオブジェクトを作成します。
Monster mon1 = new Monster(“1体目”);
そして、start()メソッドを呼び出します。
mon1.start();
start()メソッドは、MonsterクラスがThreadクラスから継承したメソッドです。このメソッドを呼び出すと、
新しいメソッドが起動し、run()メソッドの処理がされる。
このため、run()メソッドの処理が行われて、「一体目の処理をしています。」というメッセージが繰り返し表示されるのです。
実行結果から2つの処理は、どちらがどの順番で行われるかは決まっていません。
つまり、新しくスレッドを起動すると、
処理の流れが2つになる
かのようなしくみになります。
新しく起動したスレッドは、run()メソッドが終了したところで終了します。
スレッドの操作
Threadクラスから継承されたメソッドを使うと、スレッドを操作することが可能です。
たとえば、sleep()メソッドというものを使ってみましょう。このメソッドを使うと、起動したスレッドを一時停止することができます。

実行すると、「1体目の処理」のほうが1秒ごとに出力されています。スレッドがsleep()メソッドを処理すると、()内に指定したミリ秒数だけ処理が一時停止するからです。
今度は下記のコードを見てください。

今度は、main()メソッドのほうの処理が1秒おきに出力されています。
スレッドの終了を待つ
別の処理を待って、自分の処理を再開するしくみにできます。このためには、join()メソッドを使います

join()メソッドのあとに「main()の処理を終わります。」のメッセージが必ず最後に出力されます。
もうひとつのスレッドの作成方法を知る
スレッドを作成するのにThreadクラスを拡張したクラスを使ってきました。
しかし、ほかのクラスを継承しなければならない場合はどうでしょう?
Javaでは2つ以上のクラスから多重継承することができない
ことになっています。
このようなとき、クラスライブラリのRunnableインターフェースを使い、スレッドを起動するしくみをつくることができます。Threadクラスを拡張するのではなく、Runnableインターフェースを実装するコードを書くのです。
つまり、スレッドを起動するには、
- Threadクラスを拡張する
- Runnableインターフェースを実装する
という2つの方法があるわけです。

Sample15_03_6のMonsterクラスは、Runnableインターフェースを実装したクラスとなっています。
16行目~20行目のコードを見てください。Threadクラスのオブジェクトを作成してから、start()メソッドを呼び出しています。
少し手間が必要ですが、実行結果はSample15_01_1と同じになります。
同期のしくみを知る
スレッドは便利なしくみですが、複数のスレッドを起動するときには、注意が必要です。
たとえば、あるモンスターにダメージを与えるキャラクターが2体います。そこでキャラクターをCharacterというクラスにして、2つのスレッドを起動するプログラムを考えました。


main()メソッドでは、
モンスターを表すMonsterクラスのオブジェクトを1つ
キャラクターを表すCharacterクラスのオブジェクトを2つ
作成しました。
Monsterクラスのオブジェクトのadd()メソッドを使い、与えたダメージ(1回50ポイント)をそれぞれ3回ずつモンスターに攻撃する処理を行います。
最終的に2人×3回×50ポイント=300ポイントがモンスターに与えるトータルダメージのはずです。
ところが、実行結果は予想と異なるトータルダメージになっています。
これは、1人のキャラクターが攻撃をしているときに、ほかのキャラクターが同時に攻撃をはじめたので、おかしなことになっているのです。
このような不具合を避けるため、あるスレッドが攻撃の処理をしている間は、別のスレッドは処理ができないようにする必要があります。
4行目をpublic synchronized void add(int a)に変更すると、
あるスレッドがメソッドを処理している間、ほかのスレッドはこのメソッドを呼び出すことができなくなります。

今度は正しい結果になりました。このように、スレッドどうしの処理のタイミングをとる仕組みを同期といいます。
この章ではスレッドの起動方法を学びました。時間のかかる処理を別のスレッドにすることにより効率の良いプログラムを作成できます。