JavaのThreadクラスjoinメソッドを完全ガイド!初心者でもわかるスレッド制御の基本
生徒
「Javaでスレッドを使っているときに、処理の順番を制御する方法ってありますか?」
先生
「はい、そのときに役立つのがThreadクラスのjoinメソッドです。java.langパッケージに含まれていて、スレッドの終了を待つことができますよ。」
生徒
「スレッドの終了を待つって具体的にどういうことなんでしょうか?」
先生
「それでは、初心者でも分かるようにjoinメソッドの基本から実際のサンプルコードまで説明していきましょう。」
1. joinメソッドとは?
joinメソッドは、あるスレッドが終了するまで他のスレッドを待機させるためのメソッドです。例えばメインスレッドがサブスレッドの処理を待ちたいときに使われます。もしjoinを使わなければ、スレッドが同時並行で動くため、処理の順番が予測しにくくなります。これに対してjoinを使うと「このスレッドが終わるまで待ってから次に進む」といった制御が可能になります。
2. joinメソッドの基本的な使い方
基本的な使い方はとてもシンプルです。対象のスレッドに対してjoinを呼び出すだけです。これにより呼び出し元スレッドは対象のスレッドが終了するまで待機します。
public class JoinExample {
public static void main(String[] args) throws InterruptedException {
Thread worker = new Thread(() -> {
for (int i = 1; i <= 3; i++) {
System.out.println("作業中: " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
worker.start();
worker.join();
System.out.println("全ての作業が終わりました");
}
}
作業中: 1
作業中: 2
作業中: 3
全ての作業が終わりました
3. joinメソッドを使わない場合との違い
joinを使わない場合、メインスレッドはサブスレッドの処理を待たずに先に進みます。その結果、処理の順番が前後することがあります。例えば下記のようにjoinを省略すると「全ての作業が終わりました」が途中で出力されてしまうことがあります。
public class NoJoinExample {
public static void main(String[] args) {
Thread worker = new Thread(() -> {
for (int i = 1; i <= 3; i++) {
System.out.println("作業中: " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
worker.start();
System.out.println("全ての作業が終わりました");
}
}
全ての作業が終わりました
作業中: 1
作業中: 2
作業中: 3
4. joinメソッドに引数を指定する使い方
joinには引数を渡すことができ、ミリ秒単位で待機時間を指定できます。この場合、指定した時間だけ待ち、その後は対象スレッドが終了していなくても次の処理に進みます。長時間処理のスレッドを完全に待たずに制御したいときに便利です。
public class JoinTimeoutExample {
public static void main(String[] args) throws InterruptedException {
Thread worker = new Thread(() -> {
try {
Thread.sleep(3000);
System.out.println("重い処理が終了しました");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
worker.start();
worker.join(1000);
System.out.println("1秒待ったので次の処理に進みます");
}
}
1秒待ったので次の処理に進みます
重い処理が終了しました
5. joinメソッドと複数スレッドの組み合わせ
複数のスレッドを順番に実行したいときもjoinが役立ちます。例えば三つのスレッドを順番に動かしたい場合、それぞれに対してjoinを呼び出すことで制御が可能です。
public class MultiJoinExample {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> System.out.println("スレッド1終了"));
Thread t2 = new Thread(() -> System.out.println("スレッド2終了"));
Thread t3 = new Thread(() -> System.out.println("スレッド3終了"));
t1.start();
t1.join();
t2.start();
t2.join();
t3.start();
t3.join();
System.out.println("全てのスレッドが終了しました");
}
}
スレッド1終了
スレッド2終了
スレッド3終了
全てのスレッドが終了しました
6. joinメソッドを使うときの注意点
joinを使うと処理の順番を制御できますが、過度に利用するとスレッドの利点である並列処理が損なわれる場合があります。すべてのスレッドにjoinをかけてしまうと、結果的に逐次処理と同じになってしまいます。また、長時間のスレッドをjoinで完全に待機するとアプリケーション全体が停止しているように見えることもあるため、タイムアウト付きのjoinをうまく活用するのが良いです。
7. java.langパッケージとThreadクラスの位置づけ
java.langパッケージはJavaで最も基本となるクラス群を含んでいます。StringやMath、Objectと並んでThreadは重要な役割を担っています。その中でもjoinメソッドはスレッド制御の基礎であり、シンプルでありながら実用的なメソッドとして多くのアプリケーション開発で利用されています。