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是一個同步方法
關鍵代碼:
while (isAlive()) {
wait(0); //如果 timeout 為零,則不考慮實際時間,在獲得通知前該線程將一直等待。
}
isAlive是 join方法的本意和目標。即使中間被喚醒(虛擬喚醒),他仍然會再次調用wait(0)來等待下一次通知。
最終,線程死的時候會調用自己的notifyAll方法,join會執行結束。
當main線程調用t.join時候,main線程會獲得線程對象t的鎖(wait 意味着拿到該對象的鎖),調用該對象的wait(等待時間),直到該對象喚醒main線程
是main線程調用對象t的join()方法:(這里的t == Object的作用, 線程t仍在運行,則執行Object t的wait()) 調度的結果是 main一直等待。
因此,main會執行t的wait()方法,會等待直到t運行結束。
所以阻塞的是main線程。
wait(long)的方法說明:當前線程必須擁有此對象監視器。在其他線程調用此對象的notify() 方法或 notifyAll() 方法,或者超過指定的時間量前,導致當前線程等待
此方法導致當前線程(稱之為 T)將其自身放置在對象的等待集中,然后放棄此對象上的所有同步要求。
出於線程調度目的(執行的動作是讓出且等待。 等待某個條件發生 isAlive,隊列可讀,隊列可寫。。),在發生以下四種情況之一前,線程 T 被禁用,且處於休眠狀態:
1)其他某個線程調用此對象的 notify 方法,並且線程 T 碰巧被任選為被喚醒的線程。
2)其他某個線程調用此對象的 notifyAll 方法。
3)其他某個線程中斷線程 T。
4)大約已經到達指定的時間。如果 timeout 為零,則不考慮實際時間,在獲得通知前該線程將一直等待。
然后,從對象的等待集中刪除線程 T,並重新進行線程調度。然后,該線程以常規方式與其他線程競爭,以獲得在該
對象上同步的權利;一旦獲得對該對象的控制權,該對象上的所有其同步聲明都將被恢復到以前的狀態,這就是調
用wait 方法時的情況。然后,線程 T 從 wait 方法的調用中返回。所以,從 wait 方法返回時,該對象和線程T 的同
步狀態與調用wait 方法時的情況完全相同。
在沒有被通知、中斷或超時的情況下,線程還可以喚醒一個所謂的虛假喚醒 (spurious wakeup,喚醒時,條件仍然不滿足)。雖然這種情況在實
踐中很少發生,但是應用程序必須通過以下方式防止其發生,即對應該導致該線程被提醒的條件進行測試,如果不
滿足該條件,則繼續等待。換句話說,等待應總是發生在循環中,如下面的示例:
synchronized (obj) {
while (<condition does not hold>)
obj.wait(timeout);
... // Perform action appropriate to condition
}
http://blog.csdn.net/hai_qing_xu_kong/article/details/43917141