Java 多線程基礎(九)join() 方法

Java 多線程基礎(九)join 方法

一、join() 方法介紹

join() 定義 Thread 類中的,作用是:把指定的線程加入到當前線程,可以將兩個交替執行的線程合併為順序執行的線程。如:線程B中調用了線程A的Join()方法,直到線程A執行完畢後,才會繼續執行線程B。

Thread 類中分別定義了: join() 、join(long millis) 和 join(long millis, int nanos) 三個方法。

①、join():等待線程t執行完畢。

②、join(long millis):等待 t 線程,等待時間是 millis 毫秒。

③、join(long millis, int nanos) :等待 t 線程,等待時間是 millis 毫秒 + nanos 納秒。

二、join() 示例

public class JoinThread {
    
    public static void main(String[] args) {
        try {
            Thread t1 = new MyThread("t1");// 新建線程t1
            t1.start();// 啟動線程
            t1.join(); // 將線程t1加入到主線程main中,並且主線程main()會等待它的完成
            System.out.println(Thread.currentThread().getName() + " main end.");
        }catch(Exception e) {
            e.printStackTrace();
        }
    }
    static class MyThread extends Thread{
        public MyThread(String name) {
            super(name);
        }
        public void run() {
            System.out.println(Thread.currentThread().getName() + " run start.");
            for(int i = 0;i < 10000;i++)
                ;
            System.out.println(Thread.currentThread().getName() + " run end.");
        }
    }
}
// 運行結果
t1 run start.
t1 run end.
main main end.

說明:

①、在「主線程main」中通過 new MyThread(“t1”) 新建「線程t1」。 接着,通過 t1.start() 啟動「線程t1」,並執行t1.join()。
②、執行t1.join()之後,「主線程main」會進入「阻塞狀態」等待t1運行結束。「子線程t1」結束之後,會喚醒「主線程main」,「主線程」重新獲取cpu執行權,繼續運行。

具體過程圖解:

三、join() 解析(基於JDK 1.8)

public final void join() throws InterruptedException {
    join(0);
}
public final synchronized void join(long millis) throws InterruptedException {
  long base = System.currentTimeMillis();
  long now = 0;
  if (millis < 0) {
    throw new IllegalArgumentException("timeout value is negative");
  }

  if (millis == 0) {
    while (isAlive()) {
      wait(0);
    }
  } else {
    while (isAlive()) {
      long delay = millis - now;
      if (delay <= 0) {
        break;
      }
      wait(delay);
      now = System.currentTimeMillis() - base;
    }
  }
}
public final synchronized void join(long millis, int nanos) throws InterruptedException {
  if (millis < 0) {
    throw new IllegalArgumentException("timeout value is negative");
  }
  if (nanos < 0 || nanos > 999999) { // 納秒值範圍在 (0 ~ 999999]
    throw new IllegalArgumentException("nanosecond timeout value out of range");
  }
  if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
    millis++;
  }
  join(millis);
}

上面源碼是在Thread 類中定義的: join() 、join(long millis) 和 join(long millis, int nanos) 三個方法。

從上面代碼中可以看到,最主要的是 join(long millis) 方法,從該方法中可以發現:當傳遞的 millis  == 0 時,會進入while(isAlive())循環;即只要子線程是活的,主線程就不停的等待。

問題
雖然t1.join() 被調用的地方是發生在「main主線程」中,但是 t1.join() 是通過「子線程t1」去調用的 join()。那麼,join() 方法中的 isAlive() 應該是判斷「子線程t1」是不是 Alive 狀態;對應的 wait(0) 也應該是「讓子線程t1」等待才對。但如果是這樣的話,t1.join() 的作用怎麼可能是「讓主線程等待,直到子線程s完成為止」呢,應該是讓”子線程等待才對(因為調用子線程對象 t1 的 wait 方法嘛)”?
答案

wait() 的作用是讓「當前線程」等待,而這裡的「當前線程」是指當前在CPU上運行的線程。所以,雖然是調用子線程的 wait() 方法,但是它是通過「主線程」去調用的;所以,休眠的是主線程,而不是「子線程」!