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; } } }
以上是join()的底層代碼,在線程A內部調用線程B的join()函數時,會暫停A線程,等線程B執行結束后才會結束暫停。如果調用的join帶有時間參數,則時間計時結束也會結束wait()過程。
上面的isAlive()和wait()的函數對象是不一樣的,isAlive對象是被調用的線程B,wait(0)的對象是對應的是正在執行的線程A。
另一個要注意的點是,線程的狀態大致分為開始、就緒、運行、阻塞和死亡,isAlive()僅在就緒或者運行時算作真,故未start的線程join無效。
下面舉個例子
設置兩個線程類 ,並在一個子線程中調用另一個線程的join方法。
public class Thread1 extends Thread { public Thread1(String name) { super(name); } @Override public void run() { for (int i = 0; i < 3; i++) { System.out.println(Thread.currentThread().getName() + ":"+i); } } }
public class Thread2 extends Thread { public Thread2(String name) { super(name); } @Override public void run() { Thread1 B = new Thread1("B"); B.start(); try { B.join(); } catch (InterruptedException e) { e.printStackTrace(); } for (int i = 0; i < 3; i++) { System.out.println(Thread.currentThread().getName() + ":"+i); } } }
主類中按一定次序啟用線程
public class ThreadTest { public static void main(String[] args) throws InterruptedException { Thread2 A = new Thread2("A"); Thread1 C = new Thread1("C"); Thread1 D = new Thread1("D"); Thread1 E = new Thread1("E"); C.start(); A.start(); D.start(); D.join(); E.start(); } }
得到結果如下
可以看到,在A中啟用B的join方法時,並未影響到主線程,主線程仍然向后運行並開啟了D,而A只能在B之后得到運行。主線程中啟用D的join方法后,則暫停執行,即E暫時無法start。