こんにちは。ハンドルネーム「Javaを復習する初心者」です。このサイトはプログラミング言語Javaの復習・学習をするブログです。プログラムの開発・実行はEclipseで行ってます。
スポンサーリンク
お知らせ
  • 参考文献のページ作りました。
  • Amazon.co.jpアソシエイトに参加していますが、参考文献の紹介はもしもアフィリエイトに統一しました。
  • 2016年10月9日からは投稿ペースを落とします。週1回くらいにする予定です。
スポンサーリンク

複数スレッドを順番に実行する

こんにちは。「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がスタートしたことが分かります。