Javaでのマルチスレッドプログラミングを見てみます。
ThreadとRunnableの違い、sleepとwaitの違いを確認していきます。
スレッドとは
スレッドとは、プログラム上で複数の処理を同時に動かす仕組みです。
みなさんが何か作業を行う時に、一人で作業の全てをこなすより、複数人で手分けして作業したほうが早く終わるでしょう。
Javaのプログラムも同様に、処理を複数同時に動かせば、短時間で処理を終わらせることができるのです。
Thread と Runnable
スレッドを使用するには Threadクラス を継承するサブクラスを作成する方法と、Runnableインタフェース を実装したクラスを作成する方法があります。
(どちらも run() メソッドをオーバライドする必要があります)
Threadクラスを継承してスレッドを作成する場合には、Javaの単一継承というルールにより他のクラスが継承できなくなるのが注意点です。
Runnableインタフェースを実装してスレッドを作成する場合には、一度Runnableインタフェースを実装したクラスをインスタンス化し、さらにそのインスタンス化したオブジェクトをThreadクラスのコンストラクタに渡して、Threadクラス型のオブジェクトを作成すると言う、ちょっと一手間かかるというデメリットもあります。
ここで注意すべき点は、作成したクラスのrun()メソッドをスレッドで実行するためにはstart()メソッドを呼び出すと言うことです。
サンプルプログラム
ここでサンプルプログラムです。
【TestRunクラス】
public class TestRun implements Runnable { private int judge; @Override public synchronized void run() { try { if (Thread.currentThread().getName().equals("Tr-1")) { System.out.println(Thread.currentThread().getName() + "がwaitします。"); wait(); System.out.println(Thread.currentThread().getName() + "が動き出しました。"); System.out.println("judge の値は、" + judge + "です。"); } else if (Thread.currentThread().getName().equals("Tr-2")) { System.out.println(Thread.currentThread().getName() + "がwaitします。"); wait(); System.out.println(Thread.currentThread().getName() + "が動き出しました。"); System.out.println("judge の値は、" + judge + "です。"); } else { judge = 10; System.out.println(Thread.currentThread().getName() + "がsleepします。"); Thread.sleep(100); System.out.println(Thread.currentThread().getName() + "が notify をコールします。"); notify(); System.out.println(Thread.currentThread().getName() + "はそのまま動きます。"); } } catch(InterruptedException e) { System.out.println(e); } System.out.println(Thread.currentThread().getName() + "が終了しました。"); } }
【JikkoThreadクラス】
public class JikkoThread { public static void main(String[] args) { TestRun tr = new TestRun(); Thread t1 = new Thread(tr, "Tr-1"); Thread t2 = new Thread(tr, "Tr-2"); Thread t3 = new Thread(tr, "Tr-3"); t1.start(); for(int i = 0; i < 1000000; i++); t2.start(); for(int i = 0; i < 1000000; i++); t3.start(); } }
実行結果
Tr-1がwaitします。 Tr-2がwaitします。 Tr-3がsleepします。 Tr-3が notify をコールします。 Tr-3はそのまま動きます。 Tr-3が終了しました。 Tr-1が動き出しました。 judge の値は、10です。 Tr-1が終了しました。
try 〜 catch
マルチスレッド関連のメソッドを実行する時には、InterruptedExceptionが発生する可能性があるため try 〜 catch で囲う必要があります。
sleep() と wait()
今回のサンプルでは、TestRunクラスの20行目に sleep()メソッド、9行目と14行目に wait()メソッドの処理があります。
sleep()メソッドとwait()メソッドの違いは、sleep()メソッドは指定された時間が経過したら待ち状態が解除されるのに対し、wait()メソッドは他のスレッドから解除(notify)されることを前提としています。
notify()メソッド
wait()されているスレッドがある場合、notify()メソッドを実行することで待ち状態が解除されます。
ただし、今回のサンプルを確認して見ると、「Tr-3」がnotifyをコールした後で待ち状態が解除されているのは「Tr-1」のみです。
つまり、notify()メソッドでは、1つのwaitしか解除されません。
今回のようにwaitされているスレッドが複数あり、全ての待ち状態を解除したいのであれば、notifyAll()メソッドを使用します。
waitをしたら必ずnotifyをコールしないと、スレッドが待ち状態のままになってしまいます。ですので、wait()メソッドとnotifiy()メソッドは必ずペアで使用する事になります。
まとめ
このように、Javaのwait()やnotify()をマスターすれば、マルチスレッドの処理を行う時に便利に活用できますので、いろいろと試してみましょう。