[ Java Gold 対策 ] はじめてのスレッド 5日目 : joinメソッドで順番待ち

joinメソッドの使い方

シリーズ一覧
[Java Gold対策] はじめてのスレッド 1日目 : スレッドとは?
[Java Gold対策] はじめてのスレッド 2日目 : スレッドの作り方
[Java Gold対策] はじめてのスレッド 3日目 : スレッドの作り方2
[Java Gold対策] はじめてのスレッド <よりみち1> : 匿名クラスで書く。
[Java Gold対策] はじめてのスレッド <よりみち2> : ラムダ式で書く。
[Java Gold対策] はじめてのスレッド 4日目 : スレッドをsleepさせよう
[Java Gold対策] はじめてのスレッド 5日目 : joinメソッドで待たせる
[Java Gold対策] はじめてのスレッド 6日目 : runメソッドで条件付き停止

目次

スレッドを順番待ちさせよう

[ Java Gold 対策 ] はじめてのスレッド 4日目に引き続き、スレッドの処理を制御してくれるメソッドを紹介していきます。
今回紹介するのは、スレッドを順番待ちさせられる「joinメソッド」です!

こんなときに使える

初回にお話した、「Webサイトの例え話」は覚えていますでしょうか?(覚えていなくても大丈夫ですよ)
テキストと画像が含まれるWebサイトの表示を、速い方から先にできたら良いよね、といったお話でした。
ですが今回は、その逆の場合を考えてみます。

Webサイトの画像とテキストはすべて揃ってから表示したい、と考えたとします。
作業自体は効率化のために、2つのスレッドでそれぞれの保存をさせていきます。
すると、先に終わったスレッドが、まだ処理中のスレッドの終了を待つ必要が出てきますよね。
(たとえば、テキストはすぐに保存が終わって表示できてしまうけれど、画像と揃えて表示したい、というときですね)

そんなときに使えるのが、joinメソッドです!
スレッドAの処理の中で、スレッドBのjoinメソッドを呼び出せば、AはBの処理が終わるまで処理を停止して待機してくれます。

「待つスレッド」の処理の中で、「待たれるスレッド」のjoinメソッドを呼び出します。

言葉で見るとややこしいので、コードを確認していきましょう!

具体的に見てみる

class JoinThread extends Thread {
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("runメソッド(" + i + ")");
        }
    }
}

public class JoinSample {
	public static void main(String[] args) {
		JoinThread t = new JoinThread();
		t.start();
		
		try {
			// スレッドtの処理が終わるまで待機させる
			// 停止させたいスレッドのインスタンスから、joinメソッドを呼び出す
			t.join();
		} catch (InterruptedException e) {
			System.out.println(e);
		}
		
		// JoinThreadのrunメソッドの処理が終わった後で、
		// mainメソッドの処理が始まる
		for (int i = 0; i < 5; i++) {
			System.out.println("mainメソッド(" + i + ")");
		}
	}
}

実行結果: runメソッドが最後まで終わってから、mainメソッドの処理が始まる

runメソッド(0)
runメソッド(1)
runメソッド(2)
runメソッド(3)
runメソッド(4)
mainメソッド(0)
mainメソッド(1)
mainメソッド(2)
mainメソッド(3)
mainメソッド(4)

前回の同時進行で処理が進んでいた結果と違い、「runメソッドの処理」が終わってから、「mainメソッドの処理」が始められることが分かりますね!

ここで注意なのは、繰り返しになりますが、17行目のコード、
「待つスレッド」の処理の中で、「待たれるスレッド」のjoinメソッドを呼び出すという点です。

今回はmainメソッドを待たせたいため、mainメソッドの処理の流れの中で、runメソッドを実行するスレッドのインスタンス=「t」の「joinメソッド」を呼び出します。

例外処理が必要。

前回のsleepメソッドでも例外処理が必要でしたが、同様にjoinメソッドでも必要です。
今回も、「InterruptedException」が発生するので、14~20行目でtry-catch文で囲んでいますね。

InterruptedException (おさらい)
あるスレッドが長い間一時停止している間に、他のスレッドが 割り込みをかけた場合にスローされます。
Exceptionクラスのサブクラスで、検査例外です。
→例外処理が必須です。

ラムダ式でも書いてみる

public class JoinLamda {
	public static void main(String[] args) {
		Thread t = new Thread(() -> {
			for (int i = 0; i < 5; i++) {
				System.out.println("runメソッド(" + i + ")");
			}
		});
		t.start();

		try {
			t.join();
		} catch (InterruptedException e) {
			System.out.println(e);
		}

		for (int i = 0; i < 5; i++) {
			System.out.println("mainメソッド(" + i + ")");
		}
	}
}

1個前のサンプルコードではThreadクラスを継承して新しいスレッドを作っていましたが、
今回はラムダ式で書くためにRunnableインターフェイスを実現して新しいスレッドを作っています。

ラムダ式の中で、runメソッドの実装を書いて、それをThreadクラスのコンストラクタに与えることで、その1行のコードで「実装・スレッド作成」を書ききれています(3~7行目)
クラスも一つでよくなり、とってもスッキリしましたね!


今日はこれでおしまいです。
スレッドの一時停止、順番待ちまで学習が進みましたので、次回は最後の「スレッドを条件付きで止める」という方法を学んでいきましょう!

では、お楽しみに

よかったらシェアしてね!

この記事を書いた人

株式会社NEUGATEは、都内で企業研修や職業訓練を運営している会社です。主に、IT系の教育事業に力を入れています。
この記事は、株式会社NEUGATEの教育事業部が執筆をしています。

企業ホームページ:https://neugate.co.jp/

コメント

コメントする