Revised: Mar./23rd/2002
マルチスレッドでは、あるスレッドの実行終了を待機していたい場合があります。このようなときには、 join()
メソッドが利用できます。
public final void join() throws InterruptedException
このメソッドをスレッドに対して呼び出すと、当該スレッドが終了するまで、呼び出し元のスレッドが待機します。
SimpleSyncTest.java
:
// マルチスレッドで実行するクラス class SimpleSync1 implements Runnable { public void run() { System.out.println("\t" + "子供スレッド 1 開始"); System.out.println("\t" + "子供スレッド 1 終了"); } } // マルチスレッドで実行するクラス class SimpleSync2 implements Runnable { public void run() { System.out.println("\t\t" + "子供スレッド 2 開始"); System.out.println("\t\t" + "子供スレッド 2 終了"); } } // コントロールクラス class SimpleSyncTest { public static void main(String[] args) { // 子スレッドのインスタンス化 System.out.println("SimpleSync1 スレッド化"); SimpleSync1 sync1 = new SimpleSync1(); Thread thre1 = new Thread(sync1); // 子スレッドのインスタンス化 System.out.println("SimpleSync2 スレッド化"); SimpleSync2 sync2 = new SimpleSync2(); Thread thre2 = new Thread(sync2); // 子スレッドの開始 thre1.start(); thre2.start(); // 子スレッドが終了するまで待機 System.out.println("thre1, thread2 の終了を待機"); try { thre1.join(); thre2.join(); } catch (InterruptedException e) { System.out.println(e); } System.out.println("子スレッド完了"); } }
main
メソッドでは二つのスレッドをインスタンス化していますが、開始したあと、それらのメソッドが実際に実行されて終了するまで待機し、二つのスレッドが終了して初めてメッセージを出力します。
C:\Java\Thread>javac SimpleSyncTest.java C:\Java\Thread>java SimpleSyncTest SimpleSync1 スレッド化 SimpleSync2 スレッド化 thre1, thread2 の終了を待機 子供スレッド 1 開始 子供スレッド 1 終了 子供スレッド 2 開始 子供スレッド 2 終了 子スレッド完了 C:\Java\Thread>
この仕組みを用いて、実際に複数のスレッドでデータを共有してみます。
SyncTest.java
:
// 共有するデータを保持するクラス class Share { private int[] x, y; public int[] getX() { return x; } public void setX(int[] a) { x = a; } public int[] getY() { return y; } public void setY(int[] a) { y = a; } } // マルチスレッドで実行するクラス class Sync implements Runnable { // 共有データオブジェクト private Share pers; public void run() { System.out.println("\t" + "子供スレッド 1 開始"); int[] x = new int[9]; for (int i = 0; i < 9; i++) { x[i] = i + 1; } // 共有データへの書き込み pers.setX(x); System.out.println("\t" + "子供スレッド 1 終了"); } // 共有データオブジェクトの受け取り public void setPers(Share obj) { pers = obj; } } // マルチスレッドで実行するクラス class Sync2 implements Runnable { // 共有データオブジェクト private Share pers; public void run() { System.out.println("\t\t" + "子供スレッド 2 開始"); int[] x = new int[9]; for (int i = 0; i < 9; i++) { x[i] = i + 1; } // 共有データへの書き込み pers.setY(x); System.out.println("\t\t" + "子供スレッド 2 終了"); } // 共有データオブジェクトの受け取り public void setPers(Share obj) { pers = obj; } } // コントロールクラス class SyncTest { public static void main(String[] args) { // 共有データを保持するオブジェクト Share pers = new Share(); // 子スレッドのインスタンス化 System.out.println("Sync1 スレッド化"); Sync sync1 = new Sync(); Thread thre1 = new Thread(sync1); sync1.setPers(pers); // 子スレッドのインスタンス化 System.out.println("Sync2 スレッド化"); Sync2 sync2 = new Sync2(); Thread thre2 = new Thread(sync2); sync2.setPers(pers); // 子スレッドの開始 thre1.start(); thre2.start(); // 子スレッドが終了するまで待機 System.out.println("thre1, thread2 の終了を待機"); try { thre1.join(); thre2.join(); } catch (InterruptedException e) { System.out.println(e); } System.out.println("子スレッド完了"); // 子スレッドが処理したデータを利用 int[] x = pers.getX(); int[] y = pers.getY(); for (int i=0; i < x.length; i++) { for (int j=0; j < y.length; j++) { int mul = x[i] * y[j]; if (mul < 10) { System.out.print(" " + mul +" "); } else { System.out.print(mul +" "); } } System.out.println(""); } } }
この例では、 main
のスレッドが二つの子供スレッドを作っています。そして、 main
スレッドは子供スレッドが終了するのを待機して、最後にメッセージを出力しています。
C:\Java\Thread>javac SyncTest.java C:\Java\Thread>java SyncTest Sync1 スレッド化 Sync2 スレッド化 thre1, thread2 の終了を待機 子供スレッド 1 開始 子供スレッド 1 終了 子供スレッド 2 開始 子供スレッド 2 終了 子スレッド完了 1 2 3 4 5 6 7 8 9 2 4 6 8 10 12 14 16 18 3 6 9 12 15 18 21 24 27 4 8 12 16 20 24 28 32 36 5 10 15 20 25 30 35 40 45 6 12 18 24 30 36 42 48 54 7 14 21 28 35 42 49 56 63 8 16 24 32 40 48 56 64 72 9 18 27 36 45 54 63 72 81 C:\Java\Thread>
通常は、子スレッドが終了するのを待つことで、子スレッドによって完成された処理を受け継いで何らかの処理をできるようになるわけです。このサンプルでは、子スレッドは共有オブジェクトに配列を作って、これを親スレッドが受け取って九々表を作っています。
データを持続的 (persistent) にしたい場合は、共有データを保持しているクラスでファイルに書き込むか、 JDBC を用いて DB に書き込みます。