JavaのThread.join()メソッド

JavaのThread.join()メソッド

 

1. 概要

このチュートリアルでは、Threadクラスのさまざまなjoin()メソッドについて説明します。 これらのメソッドの詳細といくつかのサンプルコードについて説明します。

wait()notify() methodsと同様に、join()はスレッド間同期のもう1つのメカニズムです。

this tutorialをざっと見て、wait()notify()の詳細を読むことができます。

2. Thread.join()メソッド

結合メソッドは、Threadクラスで定義されています。

public final void join()throws InterruptedException このスレッドが死ぬのを待ちます。

スレッドでjoin()メソッドを呼び出すと、呼び出し元のスレッドは待機状態になります。 参照されるスレッドが終了するまで、待機状態のままになります。

この動作は次のコードで確認できます。

class SampleThread extends Thread {
    public int processingCount = 0;

    SampleThread(int processingCount) {
        this.processingCount = processingCount;
        LOGGER.info("Thread Created");
    }

    @Override
    public void run() {
        LOGGER.info("Thread " + this.getName() + " started");
        while (processingCount > 0) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                LOGGER.info("Thread " + this.getName() + " interrupted");
            }
            processingCount--;
        }
        LOGGER.info("Thread " + this.getName() + " exiting");
    }
}

@Test
public void givenStartedThread_whenJoinCalled_waitsTillCompletion()
  throws InterruptedException {
    Thread t2 = new SampleThread(1);
    t2.start();
    LOGGER.info("Invoking join");
    t2.join();
    LOGGER.info("Returned from join");
    assertFalse(t2.isAlive());
}

コードを実行すると、次のような結果が期待できます。

INFO: Thread Created
INFO: Invoking join
INFO: Thread Thread-1 started
INFO: Thread Thread-1 exiting
INFO: Returned from join

The join() method may also return if the referenced thread was interrupted。 この場合、メソッドはInterruptedExceptionをスローします。

最後に、if the referenced thread was already terminated or hasn’t been started, the call to join() method returns immediately

Thread t1 = new SampleThread(0);
t1.join();  //returns immediately

3. タイムアウトのあるThread.join()メソッド

join()メソッドは、参照されたスレッドがブロックされているか、処理に時間がかかりすぎる場合、待機し続けます。 呼び出しスレッドが応答しなくなるため、これが問題になる可能性があります。 これらの状況を処理するために、タイムアウト期間を指定できるjoin()メソッドのオーバーロードバージョンを使用します。

join()メソッドをオーバーロードする2つのtimed versionsがあります。

“public final void join(long millis_)はInterruptedException_をスローしますWaits at mostミリ秒 milliseconds for this thread to die. A timeout of 0 means to wait forever.”

“public final void join(long millis、int nanos_)は、InterruptedException _Waits at most millis milliseconds plus nanos_ nanosecondsをスローして、このスレッドを終了させます。」_

時限join()を次のように使用できます。

@Test
public void givenStartedThread_whenTimedJoinCalled_waitsUntilTimedout()
  throws InterruptedException {
    Thread t3 = new SampleThread(10);
    t3.start();
    t3.join(1000);
    assertTrue(t3.isAlive());
}

この場合、呼び出しスレッドは、スレッドt3が終了するまで約1秒間待機します。 スレッドt3がこの期間内に終了しない場合、join()メソッドは呼び出し元のメソッドに制御を戻します。

タイミングjoin()は、タイミングについてOSに依存します。 したがって、join()が指定された時間だけ待機するとは限りません。

4. Thread.join()メソッドと同期

終了まで待機することに加えて、join()メソッドを呼び出すと同期効果があります。 join() creates a happens-before relationship:

「スレッド内のすべてのアクションは、他のスレッドがそのスレッドのjoin()から正常に戻る前に発生します。」

つまり、スレッドt1がt2.join()を呼び出すと、t2によって行われたすべての変更が、戻り時にt1に表示されます。 ただし、join()を呼び出さない場合、または他の同期メカニズムを使用しない場合、他のスレッドが完了した場合でも、他のスレッドの変更が現在のスレッドに表示される保証はありません。

したがって、終了状態のスレッドへのjoin()メソッド呼び出しはすぐに返されますが、状況によってはそれを呼び出す必要があります。

不適切に同期されたコードの例を以下に示します。

SampleThread t4 = new SampleThread(10);
t4.start();
// not guaranteed to stop even if t4 finishes.
do {

} while (t4.processingCount > 0);

上記のコードを適切に同期するために、ループ内に時間指定されたt4.join()を追加するか、他の同期メカニズムを使用できます。

5. 結論

join()メソッドは、スレッド間の同期に非常に役立ちます。 この記事では、join()メソッドとその動作について説明しました。 また、join()メソッドを使用してコードを確認しました。

いつものように、完全なソースコードはover on GitHubにあります。