Java Thread.join()詳解--父線程等待子線程結束后再結束


目錄(?)[+]

 

join是Thread類的一個方法,啟動線程后直接調用,例如:

 

?
1
Thread t =  new AThread(); t.start(); t.join();
回到頂部

在很多情況下,主線程生成並起動了子線程,如果子線程里要進行大量的耗時的運算,主線程往往將於子線程之前結束,但是如果主線程處理完其他的事務后,需要用到子線程的處理結果,也就是主線程需要等待子線程執行完成之后再結束,這個時候就要用到join()方法了。

 

回到頂部

在JDk的API里對於join()方法是:

 

join

public final void join() throws InterruptedException Waits for this thread to die. Throws: InterruptedException  - if any thread has interrupted the current thread. The interrupted status of the current thread is cleared when this exception is thrown.

回到頂部

寫一個簡單的例子來看一下join()的用法:

 

1.AThread 類

BThread類

  1. TestDemo 類

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    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" );
             }
         }
    }
    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!" );
         }
    }

    打印結果:

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    main start.     // 主線程起動,因為調用了at. join (),要等到at結束了,此線程才能向下執行。
    [BThread] Thread start.
    [BThread] Thread loop at 0
    [BThread] Thread loop at 1
    [AThread] Thread start.     // 線程at啟動,因為調用bt. join (),等到bt結束了才向下執行。
    [BThread] Thread loop at 2
    [BThread] Thread loop at 3
    [BThread] Thread loop at 4
    [BThread] Thread end.
    [AThread] Thread end.     // 線程AThread在bt. join ();阻塞處起動,向下繼續執行的結果
    main end!       // 線程AThread結束,此線程在at. join ();阻塞處起動,向下繼續執行的結果。
    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    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(); //在此處注釋掉對join()的調用
             catch (Exception e) {
                 System.out.println( "Exception from main" );
             }
             System.out.println(threadName +  " end!" );
         }
    }

    打印結果:

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    main start.     // 主線程起動,因為Thread. sleep (2000),主線程沒有馬上結束;
     
    [BThread] Thread start.     // 線程BThread起動
    [BThread] Thread loop at 0
    [BThread] Thread loop at 1
    main end!    // sleep 兩秒后主線程結束,AThread執行的bt. join ();並不會影響到主線程。
    [AThread] Thread start.     // 線程at起動,因為調用了bt. join (),等到bt結束了,此線程才向下執行。
    [BThread] Thread loop at 2
    [BThread] Thread loop at 3
    [BThread] Thread loop at 4
    [BThread] Thread end.     // 線程BThread結束了
    [AThread] Thread end.     // 線程AThread在bt. join ();阻塞處起動,向下繼續執行的結果

    五、從源碼看join()方法

    在AThread的run方法里,執行了bt.join();,進入看一下它的JDK源碼:

    ?
    1
    2
    3
    public final void join()  throws InterruptedException {
         join(0L);
    }
    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    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)
             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 );
    }

    單純從代碼上看: * 如果線程被生成了,但還未被起動,isAlive()將返回false,調用它的join()方法是沒有作用的。將直接繼續向下執行。 * 在AThread類中的run方法中,bt.join()是判斷bt的active狀態,如果bt的isActive()方法返回false,在 bt.join(),這一點就不用阻塞了,可以繼續向下進行了。從源碼里看,wait方法中有參數,也就是不用喚醒誰,只是不再執行wait,向下繼續執 行而已。 * 在join()方法中,對於isAlive()和wait()方法的作用對象是個比較讓人困惑的問題:

    isAlive()方法的簽名是:public final native boolean isAlive(),也就是說isAlive()是判斷當前線程的狀態,也就是bt的狀態。

    wait()方法在jdk文檔中的解釋如下:

    Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object. In other words, this method behaves exactly as if it simply performs the call wait(0).

    The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the notify method or the notifyAll method. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.

    在這里,當前線程指的是at。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM