代碼一:
public static void main(String[] args) throws Exception {
Thread thread = new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(10);
System.out.println("thread-0 thread exit.");
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "thread-0");
thread.start();
thread.join();
System.out.println("main thread exit.");
}
控制臺(10s后打印并退出):
thread-0 thread exit.
main thread exit.
Process finished with exit code 0
代碼二:
public static void main(String[] args) throws Exception {
Thread.currentThread().join();
System.out.println("main thread exit.");
}
控制臺(一直等待中):
問題:第一段代碼是main線程阻塞在thread-0線程上,當(dāng)thread-0執(zhí)行完畢,main線程也同時退出,那第二段代碼中main線程阻塞在哪個線程上呢,為什么沒有退出?
public static void main(String[] args) throws Exception {
Thread.currentThread().join();
System.out.println("main thread exit.");
}
為了了解問題本質(zhì),我們跟進(jìn)去代碼看看,線程的join方法如下:
public final void join() throws InterruptedException {
join(0);
}
再繼續(xù)跟:
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;
}
}
}
根據(jù)代碼,其實(shí)join方法最終是待用了wait(0);這行代碼,而wait方法是本地方法.
根據(jù)wait的方法定義,有以下幾點(diǎn)逐一說明:
<ul>
<li>Some other thread invokes the {@code notify} method for this
object and thread <var>T</var> happens to be arbitrarily chosen as
the thread to be awakened.
<li>Some other thread invokes the {@code notifyAll} method for this
object.
<li>Some other thread {@linkplain Thread#interrupt() interrupts}
thread <var>T</var>.
<li>The specified amount of real time has elapsed, more or less. If
{@code timeout} is zero, however, then real time is not taken into
consideration and the thread simply waits until notified.
</ul>
因此,回答你的問題就是,join方法實(shí)質(zhì)是調(diào)用了wait方法.wait方法調(diào)用后阻塞(我不認(rèn)為這是阻塞)在當(dāng)前線程(main線程上),根據(jù)wait的定義,不調(diào)用notify,notifyAll,interrupt以及超時機(jī)制(本例調(diào)用的是wait(0),故不存在這種情況),那么線程將一直處于等待狀態(tài),故一直不會退出。
大致的說下吧,Thread中,join()方法的作用是調(diào)用線程等待該線程完成后,才能繼續(xù)用下運(yùn)行。
public static void main(String[] args) throws InterruptedException
{
System.out.println("main start");
Thread t1 = new Thread(new Worker("thread-1"));
t1.start();
t1.join();
System.out.println("main end");
}
在上面的例子中,main線程要等到t1線程運(yùn)行結(jié)束后,才會輸出“main end”。如果不加t1.join(),main線程和t1線程是并行的。而加上t1.join(),程序就變成是順序執(zhí)行了。
我們在用到j(luò)oin()的時候,通常都是main線程等到其他多個線程執(zhí)行完畢后再繼續(xù)執(zhí)行。其他多個線程之間并不需要互相等待。
下面這段代碼并沒有實(shí)現(xiàn)讓其他線程并發(fā)執(zhí)行,線程是順序執(zhí)行的。
public static void main(String[] args) throws InterruptedException
{
System.out.println("main start");
Thread t1 = new Thread(new Worker("thread-1"));
Thread t2 = new Thread(new Worker("thread-2"));
t1.start();
//等待t1結(jié)束,這時候t2線程并未啟動
t1.join();
//t1結(jié)束后,啟動t2線程
t2.start();
//等待t2結(jié)束
t2.join();
System.out.println("main end");
}
所以就會是這個結(jié)果
北大青鳥APTECH成立于1999年。依托北京大學(xué)優(yōu)質(zhì)雄厚的教育資源和背景,秉承“教育改變生活”的發(fā)展理念,致力于培養(yǎng)中國IT技能型緊缺人才,是大數(shù)據(jù)專業(yè)的國家
達(dá)內(nèi)教育集團(tuán)成立于2002年,是一家由留學(xué)海歸創(chuàng)辦的高端職業(yè)教育培訓(xùn)機(jī)構(gòu),是中國一站式人才培養(yǎng)平臺、一站式人才輸送平臺。2014年4月3日在美國成功上市,融資1
北大課工場是北京大學(xué)校辦產(chǎn)業(yè)為響應(yīng)國家深化產(chǎn)教融合/校企合作的政策,積極推進(jìn)“中國制造2025”,實(shí)現(xiàn)中華民族偉大復(fù)興的升級產(chǎn)業(yè)鏈。利用北京大學(xué)優(yōu)質(zhì)教育資源及背
博為峰,中國職業(yè)人才培訓(xùn)領(lǐng)域的先行者
曾工作于聯(lián)想擔(dān)任系統(tǒng)開發(fā)工程師,曾在博彥科技股份有限公司擔(dān)任項(xiàng)目經(jīng)理從事移動互聯(lián)網(wǎng)管理及研發(fā)工作,曾創(chuàng)辦藍(lán)懿科技有限責(zé)任公司從事總經(jīng)理職務(wù)負(fù)責(zé)iOS教學(xué)及管理工作。
浪潮集團(tuán)項(xiàng)目經(jīng)理。精通Java與.NET 技術(shù), 熟練的跨平臺面向?qū)ο箝_發(fā)經(jīng)驗(yàn),技術(shù)功底深厚。 授課風(fēng)格 授課風(fēng)格清新自然、條理清晰、主次分明、重點(diǎn)難點(diǎn)突出、引人入勝。
精通HTML5和CSS3;Javascript及主流js庫,具有快速界面開發(fā)的能力,對瀏覽器兼容性、前端性能優(yōu)化等有深入理解。精通網(wǎng)頁制作和網(wǎng)頁游戲開發(fā)。
具有10 年的Java 企業(yè)應(yīng)用開發(fā)經(jīng)驗(yàn)。曾經(jīng)歷任德國Software AG 技術(shù)顧問,美國Dachieve 系統(tǒng)架構(gòu)師,美國AngelEngineers Inc. 系統(tǒng)架構(gòu)師。