join在線程里面意味着“插隊”,哪個線程調用join代表哪個線程插隊先執行——但是插誰的隊是有講究了,不是說你可以插到隊頭去做第一個吃螃蟹的人,而是插到在當前運行線程的前面,比如系統目前運行線程A,在線程A里面調用了線程B.join方法,則接下來線程B會搶先在線程A面前執行,等到線程B全部執行完后才繼續執行線程A。
而在JDK的解釋中,join方法被解釋成等待這個線程死亡,也就是等待這個線程全部執行完后才繼續執行接下來的進程。
public class Test1 implements Runnable{ @Override public void run() { for (int i = 0; i < 20; i++) { System.out.println(Thread.currentThread().getName()+i); } } public static void main(String[] args) throws InterruptedException { Thread thread1=new Thread(new Test1(),"線程一"); Thread thread2=new Thread(new Test1(),"線程二"); Thread thread3=new Thread(new Test1(),"線程三"); thread1.start(); thread2.start(); thread3.start(); System.out.println("------------------主線程到此-------------------"); /*thread2.join(); */ for (int i = 0; i < 20; i++) { System.out.println("主線程"+i); } } }
在上面這個例子中,在主線程里面開啟了3個子線程,結果是主線程先執行完再執行其他線程。
加上讓線程2先執行完再執行主線程join后
public class Test1 implements Runnable{ @Override public void run() { for (int i = 0; i < 20; i++) { System.out.println(Thread.currentThread().getName()+i); } } public static void main(String[] args) throws InterruptedException { Thread thread1=new Thread(new Test1(),"線程一"); Thread thread2=new Thread(new Test1(),"線程二"); Thread thread3=new Thread(new Test1(),"線程三"); thread1.start(); thread2.start(); thread3.start(); System.out.println("------------------主線程到此-------------------"); thread2.join(); //讓線程2先執行完主線程才能繼續執行 for (int i = 0; i < 20; i++) { System.out.println("主線程"+i); } } }
結果是
/** * join的用法,哪個線程調用join哪個線程就插隊先執行 */ public class Test{ public static void main(String[] args) throws InterruptedException { //開啟Father線程,滿足Father需求 new Thread(new Father()).start(); } } class Father implements Runnable{ @Override public void run() { System.out.println("老爸要抽煙,發現沒煙了,給了100塊讓兒子去買中華......"); Thread son=new Thread(new Son()); //讓兒子去買煙 son.start(); //開啟兒子線程后,兒子線程進入就緒狀態等待CPU調度,不一定立即執行兒子線程,所以可能會出現兒子沒把煙買回來老爸就有煙抽了 /* try { son.join(); //讓兒子先插隊去買煙 } catch (InterruptedException e) { e.printStackTrace(); System.out.println("兒子不見了,報警尋找"); }*/ System.out.println("老爸接過煙,把零錢給了兒子"); System.out.println("兒子很開心,出門去了游戲廳"); } } class Son implements Runnable{ @Override public void run() { System.out.println("兒子接過錢蹦躂出了門"); System.out.println("路過游戲廳玩了10秒鍾"); for (int i = 1; i <= 10; i++) { System.out.println(i+"秒"); try { Thread.sleep(1000); //此時休眠可能會讓其他線程進行,出錯率增加,通過join方法解決 } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("趕緊去買煙"); System.out.println("回家把煙給老爸"); } }
加入了join方法后,運行結果正確
try { son.join(); //讓兒子先插隊去買煙 } catch (InterruptedException e) { e.printStackTrace(); System.out.println("兒子不見了,報警尋找"); }