Java Thread.joinの詳細

5457 ワード

一、使用方法
          Thread t = new AThread();
          t.start();
          t.join();
二、なぜjoin()メソッドを使うのか多くの場合、メインスレッドはサブスレッドを生成して起動し、サブスレッドで大量の時間の演算を行う場合、メインスレッドはサブスレッドの前に終了することが多いが、メインスレッドが他のトランザクションを処理した後、サブスレッドの処理結果を使用する必要がある.つまり、メインスレッドはサブスレッドの実行が完了してから終了するのを待つ必要がある.この時はjoin()メソッドを使います.
三、joinメソッドの役割JDKではjoinメソッドを「スレッドの終了を待つ」と解釈し、言い換えれば「現在のスレッドがサブスレッドの終了を待つ」と解釈する.つまり、サブスレッドがjoin()メソッドを呼び出した後のコードは、サブスレッドが現在のスレッドを終了するまで実行できない.
四、実例で理解する
1.join()の使い方を簡単に理解する:
public class BThread extends Thread {

	public BThread() {
		super("[BThread] Thread");
	};

	public void run() {
		String threadName = Thread.currentThread().getName();
		System.out.println(threadName + " start.");
		try {
			for (int i = 0; i < 5; i++) {
				System.out.println(threadName + " loop at " + i);
				Thread.sleep(1000);
			}
			System.out.println(threadName + " end.");
		} catch (Exception e) {
			System.out.println("Exception from " + threadName + ".run");
		}
	}
}

public class AThread extends Thread {

    BThread bt;

    public AThread(BThread bt) {
        super("[AThread] Thread");
        this.bt = bt;
    }

    public void run() {
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName + " start.");
        try {
            bt.join();
            System.out.println(threadName + " end.");
        } catch (Exception e) {
            System.out.println("Exception from " + threadName + ".run");
        }
    }
}

public class TestDemo {

    public static void main(String[] args) {
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName + " start.");
        BThread bt = new BThread();
        AThread at = new AThread(bt);
        try {
            bt.start();
            Thread.sleep(2000);
            at.start();
            at.join();
        } catch (Exception e) {
            System.out.println("Exception from main");
        }
        System.out.println(threadName + " end!");
    }

}

実行結果:
main start.                  --      ,          at.join(),          AThread          
[BThread] Thread start.
[BThread] Thread loop at 0
[BThread] Thread loop at 1
[AThread] Thread start.      -- AThread    ,   AThread      bt.join(),   AThread     BThread          
[BThread] Thread loop at 2
[BThread] Thread loop at 3
[BThread] Thread loop at 4
[BThread] Thread end.        -- BThread     , AThread    
[AThread] Thread end.        -- AThread     ,      
main end!

2.join()の使い方を深く理解する:
ネット上ではjoin()の使い方をこのように説明している人がたくさんいます.「メインスレッドはサブスレッドの終了を待っている」と、多くの人がそう言っていると信じていますが、この言い方は完全に間違っています.なぜですか.
例を見てください.上のコードに基づいて、TestDemoクラスを変更します.
public class TestDemo {

	public static void main(String[] args) {
		String threadName = Thread.currentThread().getName();
		System.out.println(threadName + " start.");
		BThread bt = new BThread();
		AThread at = new AThread(bt);
		try {
			bt.start();
			Thread.sleep(2000);
			at.start();
			// at.join();  //     
		} catch (Exception e) {
			System.out.println("Exception from main");
		}
		System.out.println(threadName + " end!");
	}
}
実行結果:
main start.                     --      
[BThread] Thread start.         -- BThread    
[BThread] Thread loop at 0
[BThread] Thread loop at 1
main end!                       --      ,(    AThread      bt.join()         )
[AThread] Thread start.         -- AThread    ,   AThread      bt.join(),   AThread     BThread          
[BThread] Thread loop at 2
[BThread] Thread loop at 3
[BThread] Thread loop at 4     
[BThread] Thread end.           -- BThread     , AThread    
[AThread] Thread end.
賢い読者がなぜ言ったのかを推測していると信じています.
プライマリスレッド
サブスレッドの終了を待つ」というエラーの原因でしょう.
現在のスレッド
サブスレッドの終了を待つ」
五、ソースコードから見たjoin()の方法
AThreadのrunメソッドではbt.join()が実行され、JDKソースコードを見てみましょう.
    public final void join() throws InterruptedException {
        join(0L);
    }

次にjoin(0 L)メソッドに入ります.
    public final synchronized void join(long l)
        throws InterruptedException
    {
        long l1 = System.currentTimeMillis();
        long l2 = 0L;
        if(l < 0L)
            throw new IllegalArgumentException("timeout value is negative");
        if(l == 0L)
            //         ,      ,isAlive()   false,    join()        ,         。
            for(; isAlive(); wait(0L));
        else
            do
            {
                if(!isAlive())
                    break;
                long l3 = l - l2;
                if(l3 <= 0L)
                    break;
                wait(l3);
                l2 = System.currentTimeMillis() - l1;
            } while(true);
    }

単純にコード的に見ると,AThreadクラスにおけるrunメソッドでは,bt.join()はbtのactive状態を判断し,btのisActive()メソッドがfalseを返し,bt.join()であれば,BThreadスレッドの終了を待たずにAThreadを下に進めることができる.
isAlive()メソッドの署名は,public final native boolean isAlive()であり,すなわちisAlive()は現在のスレッドの状態を判断する.