こんにちは。「Javaを復習する初心者」です。
今回は複数のスレッドを順番に実行する方法を試しました。
ここで「順番に」というのはスレッドが終わったら次のスレッドを実行するという意味合いです。
スレッドを定義する
以下の2つのスレッドを定義して、順番に実行することを考えます。
定義
Thread thread1 = new Thread(() -> {
System.out.println("thread1 start");
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("thread1 end");
});
Thread thread2 = new Thread(() -> {
System.out.println("thread2 start");
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("thread2 end");
});
上記は2つのスレッドを定義しています。それぞれ開始と終了に文字列を出力しています。間に5秒停止する処理があります。
終了を待たない場合
以下のようにThread#start()メソッドを続けて書いた場合、2つのスレッドが実行されることになります。
ソース
thread1.start();
thread2.start();
System.out.println("end");
結果
end
thread1 start
thread2 start
thread1 end
thread2 end
ほぼ同時に2つのスレッドが実行されるため、「thread1 start」の直後に「thread2 start」が実行されます。
終了を待つ場合
では、Thread#joinメソッドを使うとどうなるか、次のソースで試しました。
ソース
thread1.start();
try {
thread1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
thread2.start();
try {
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("end");
結果
thread1 start
thread1 end
thread2 start
thread2 end
end
joinメソッドを使った場合、メインスレッドがスレッドの停止を待つことになります。なので、「end」の出力が最後です。
ExecutorService
メインスレッドの処理を止めない方法の一つとして、ExecutorServiceインターフェースの実装クラスを使う方法があります。Executors#newSingleThreadExecutor()メソッドで取得できるインスタンスを使うとスレッドを一元的に管理できます。
ExecutorServiceインターフェースのスーパー・インターフェースはExecutorであり、このインターフェースにexecute()メソッドがあります。引数はRunnableインターフェースです。API仕様書によるとexecute()メソッドは「将来のどの時点かで、指定されたコマンドを実行します。」とあります。newSingleThreadExecutor()メソッドで取得できるインスタンスの場合、execute()メソッド一回目に指定したスレッドはすぐに実行され、直後にexecute()メソッドを使うと、そのスレッドは1つ目のスレッドが終了した後に実行されるようです。
以下、例と実行結果です。
ソース
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(thread1);
executorService.execute(thread2);
System.out.println("end");
executorService.shutdown();
結果
end
thread1 start
thread1 end
thread2 start
thread2 end
実効結果では最初に「end」が出力されています。定義したスレッドの終了を待たずに、メインスレッドの処理が進んだことが分かります。また、「thread1 end」と「thread2 start」がこの順番で出力されているので、thread1の終了後にthread2がスタートしたことが分かります。