浅析 Java Thread.join()
一、在研究join的用法之前,先明確兩件事情。
1.join方法定義在Thread類(lèi)中,則調(diào)用者必須是一個(gè)線程,
例如:
Thread t = new CustomThread();//這里一般是自定義的線程類(lèi)
t.start();//線程起動(dòng)
t.join();//此處會(huì)拋出InterruptedException異常
?
2.上面的兩行代碼也是在一個(gè)線程里面執(zhí)行的。
?
以上出現(xiàn)了兩個(gè)線程,一個(gè)是我們自定義的線程類(lèi),我們實(shí)現(xiàn)了run方法,做一些我們需要的工作;另外一個(gè)線程,生成我們自定義線程類(lèi)的對(duì)象,然后執(zhí)行
customThread.start();
customThread.join();
在這種情況下,兩個(gè)線程的關(guān)系是一個(gè)線程由另外一個(gè)線程生成并起動(dòng),所以我們暫且認(rèn)為第一個(gè)線程叫做“子線程”,另外一個(gè)線程叫做“主線程”。
?
二、為什么要用join()方法
主線程生成并起動(dòng)了子線程,而子線程里要進(jìn)行大量的耗時(shí)的運(yùn)算(這里可以借鑒下線程的作用),當(dāng)主線程處理完其他的事務(wù)后,需要用到子線程的處理結(jié)果,這個(gè)時(shí)候就要用到j(luò)oin();方法了。
?
?
三、join方法的作用
在網(wǎng)上看到有人說(shuō)“將兩個(gè)線程合并”。這樣解釋我覺(jué)得理解起來(lái)還更麻煩。不如就借鑒下API里的說(shuō)法:
“等待該線程終止。”
解釋一下,是主線程(我在“一”里已經(jīng)命名過(guò)了)等待子線程的終止。也就是在子線程調(diào)用了join()方法后面的代碼,只有等到子線程結(jié)束了才能執(zhí)行。(Waits for this thread to die.)
?
?
四、用實(shí)例來(lái)理解
寫(xiě)一個(gè)簡(jiǎn)單的例子來(lái)看一下join()的用法,一共三個(gè)類(lèi):
1.CustomThread 類(lèi)
2. CustomThread1類(lèi)
3. JoinTestDemo 類(lèi),main方法所在的類(lèi)。
?
代碼1:
?2/**??
?3?*???
?4?*?@author?bzwm??
?5?*??
?6?*/??
?7class?CustomThread1?extends?Thread?{???
?8????public?CustomThread1()?{???
?9????????super("[CustomThread1]?Thread");???
10????};???
11????public?void?run()?{???
12????????String?threadName?=?Thread.currentThread().getName();???
13????????System.out.println(threadName?+?"?start.");???
14????????try?{???
15????????????for?(int?i?=?0;?i?<?5;?i++)?{???
16????????????????System.out.println(threadName?+?"?loop?at?"?+?i);???
17????????????????Thread.sleep(1000);???
18????????????}???
19????????????System.out.println(threadName?+?"?end.");???
20????????}?catch?(Exception?e)?{???
21????????????System.out.println("Exception?from?"?+?threadName?+?".run");???
22????????}???
23????}???
24}???
25class?CustomThread?extends?Thread?{???
26????CustomThread1?t1;???
27????public?CustomThread(CustomThread1?t1)?{???
28????????super("[CustomThread]?Thread");???
29????????this.t1?=?t1;???
30????}???
31????public?void?run()?{???
32????????String?threadName?=?Thread.currentThread().getName();???
33????????System.out.println(threadName?+?"?start.");???
34????????try?{??? 35????????????t1.join();??? 36????????????System.out.println(threadName?+?"?end.");??? 37????????}?catch?(Exception?e)?{??? 38????????????System.out.println("Exception?from?"?+?threadName?+?".run");??? 39????????}??? 40????}??? 41}??? 42public?class?JoinTestDemo?{??? 43????public?static?void?main(String[]?args)?{??? 44????????String?threadName?=?Thread.currentThread().getName();??? 45????????System.out.println(threadName?+?"?start.");??? 46????????CustomThread1?t1?=?new?CustomThread1();??? 47????????CustomThread?t?=?new?CustomThread(t1);??? 48????????try?{??? 49????????????t1.start();??? 50????????????Thread.sleep(2000);??? 51????????????t.start();??? 52????????????t.join();//在代碼2里,將此處注釋掉??? 53????????}?catch?(Exception?e)?{??? 54????????????System.out.println("Exception?from?main");??? 55????????}??? 56????????System.out.println(threadName?+?"?end!");??? 57????}??? 58}
打印結(jié)果:
?
main start.//main方法所在的線程起動(dòng),但沒(méi)有馬上結(jié)束,因?yàn)檎{(diào)用t.join();,所以要等到t結(jié)束了,此線程才能向下執(zhí)行。
[CustomThread1] Thread start.//線程CustomThread1起動(dòng)
[CustomThread1] Thread loop at 0//線程CustomThread1執(zhí)行
[CustomThread1] Thread loop at 1//線程CustomThread1執(zhí)行
[CustomThread] Thread start.//線程CustomThread起動(dòng),但沒(méi)有馬上結(jié)束,因?yàn)檎{(diào)用t1.join();,所以要等到t1結(jié)束了,此線程才能向下執(zhí)行。
[CustomThread1] Thread loop at 2//線程CustomThread1繼續(xù)執(zhí)行
[CustomThread1] Thread loop at 3//線程CustomThread1繼續(xù)執(zhí)行
[CustomThread1] Thread loop at 4//線程CustomThread1繼續(xù)執(zhí)行
[CustomThread1] Thread end. //線程CustomThread1結(jié)束了
[CustomThread] Thread end.// 線程CustomThread在t1.join();阻塞處起動(dòng),向下繼續(xù)執(zhí)行的結(jié)果
main end!//線程CustomThread結(jié)束,此線程在t.join();阻塞處起動(dòng),向下繼續(xù)執(zhí)行的結(jié)果。
?
修改一下代碼,得到代碼2:(這里只寫(xiě)出修改的部分)
?
public?class?JoinTestDemo?{????2????public?static?void?main(String[]?args)?{???
?3????????String?threadName?=?Thread.currentThread().getName();???
?4????????System.out.println(threadName?+?"?start.");???
?5????????CustomThread1?t1?=?new?CustomThread1();???
?6????????CustomThread?t?=?new?CustomThread(t1);???
?7????????try?{???
?8????????????t1.start();???
?9????????????Thread.sleep(2000);???
10????????????t.start();???
11//??????????t.join();//在代碼2里,將此處注釋掉???
12????????}?catch?(Exception?e)?{???
13????????????System.out.println("Exception?from?main");???
14????????}???
15????????System.out.println(threadName?+?"?end!");???
16????}???
17}
打印結(jié)果:
?
main start. // main方法所在的線程起動(dòng),但沒(méi)有馬上結(jié)束,這里并不是因?yàn)閖oin方法,而是因?yàn)門(mén)hread.sleep(2000);
[CustomThread1] Thread start. //線程CustomThread1起動(dòng)
[CustomThread1] Thread loop at 0//線程CustomThread1執(zhí)行
[CustomThread1] Thread loop at 1//線程CustomThread1執(zhí)行
main end!// Thread.sleep(2000);結(jié)束,雖然在線程CustomThread執(zhí)行了t1.join();,但這并不會(huì)影響到其他線程(這里main方法所在的線程)。
[CustomThread] Thread start. //線程CustomThread起動(dòng),但沒(méi)有馬上結(jié)束,因?yàn)檎{(diào)用t1.join();,所以要等到t1結(jié)束了,此線程才能向下執(zhí)行。
[CustomThread1] Thread loop at 2//線程CustomThread1繼續(xù)執(zhí)行
[CustomThread1] Thread loop at 3//線程CustomThread1繼續(xù)執(zhí)行
[CustomThread1] Thread loop at 4//線程CustomThread1繼續(xù)執(zhí)行
[CustomThread1] Thread end. //線程CustomThread1結(jié)束了
[CustomThread] Thread end. // 線程CustomThread在t1.join();阻塞處起動(dòng),向下繼續(xù)執(zhí)行的結(jié)果
?
?
五、從源碼看join()方法
?
在CustomThread的run方法里,執(zhí)行了t1.join();,進(jìn)入看一下它的JDK源碼:
?
final?void?join()?throws?InterruptedException?{???2join(0);???
3}??
?
然后進(jìn)入join(0)方法:
?2????*?Waits?at?most?<code>millis</code>?milliseconds?for?this?thread?to???
?3????*?die.?A?timeout?of?<code>0</code>?means?to?wait?forever.?//注意這句??
?4????*??
?5????*?@param??????millis???the?time?to?wait?in?milliseconds.??
?6????*?@exception??InterruptedException?if?another?thread?has?interrupted??
?7????*?????????????the?current?thread.??The?<i>interrupted?status</i>?of?the??
?8????*?????????????current?thread?is?cleared?when?this?exception?is?thrown.??
?9????*/??
10???public?final?synchronized?void?join(long?millis)?//參數(shù)millis為0.???
11???throws?InterruptedException?{???
12long?base?=?System.currentTimeMillis();???
13long?now?=?0;???
14if?(millis?<?0)?{???
15???????????throw?new?IllegalArgumentException("timeout?value?is?negative");???
16}???
17if?(millis?==?0)?{//進(jìn)入這個(gè)分支???
18????while?(isAlive())?{//判斷本線程是否為活動(dòng)的。這里的本線程就是t1.???
19????wait(0);//阻塞???
20????}???
21}?else?{???
22????while?(isAlive())?{???
23????long?delay?=?millis?-?now;???
24????if?(delay?<=?0)?{???
25????????break;???
26????}???
27????wait(delay);???
28????now?=?System.currentTimeMillis()?-?base;???
29????}???
30}???
31???}?
?
單純從代碼上看,如果線程被生成了,但還未被起動(dòng),調(diào)用它的join()方法是沒(méi)有作用的。將直接繼續(xù)向下執(zhí)行,這里就不寫(xiě)代碼驗(yàn)證了。
轉(zhuǎn)載于:https://www.cnblogs.com/kabi/p/5242093.html
總結(jié)
以上是生活随笔為你收集整理的浅析 Java Thread.join()的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 如何在共生中赢天下
- 下一篇: 怎么给学生讲路域环境和行道树保护