Thread的join()方法理解
Thread的join()方法的官方文件給出的解釋是:等待該執行緒終止。我們可以參考一下程式碼
public class Student1 extends Thread {
@Override
public void run(){
for(int i=1;i<10;i++){
System.out.println(getName()+"-->"+i);
}
}
}
我們在沒有join()方法之前,執行結果:public class ReadMain { public static void main(String[] args) throws InterruptedException{ Student1 s1 = new Student1(); s1.setName("執行緒1"); //為執行緒命名 s1.start(); //s1.join(); for(int i=0;i<10;i++){ System.out.println("main-->"+i); } } }
main-->0
執行緒1-->1
main-->1
執行緒1-->2
main-->2
執行緒1-->3
main-->3
執行緒1-->4
執行緒1-->5
main-->4
執行緒1-->6
main-->5
執行緒1-->7
main-->6
執行緒1-->8
main-->7
執行緒1-->9
main-->8
main-->9
加上s1.join()方法後,結果如下:
可以看出執行緒1先執行完後,再是主執行緒main執行,join()方法的官方解釋是:等待該執行緒終止。根據上面的結果 我們可以推測是讓呼叫s1.join()的執行緒(這裡既是主執行緒main)等待被呼叫執行緒(這裡既是執行緒1)執行完後再執行呼叫s1.join()的 執行緒(main執行緒),即將呼叫執行緒(main執行緒)阻塞。執行緒1-->1 執行緒1-->2 執行緒1-->3 執行緒1-->4 執行緒1-->5 執行緒1-->6 執行緒1-->7 執行緒1-->8 執行緒1-->9 main-->0 main-->1 main-->2 main-->3 main-->4 main-->5 main-->6 main-->7 main-->8 main-->9
這裡只有兩個執行緒,我們現在在新增兩個執行緒執行緒2和執行緒3,觀察輸出結果:
我們根據上面的結果可以得出其執行的順序:執行緒1-->1 執行緒3--->0 執行緒2:-->1 執行緒3--->1 執行緒1-->2 執行緒3--->2 執行緒2:-->2 執行緒3--->3 執行緒1-->3 執行緒3--->4 執行緒2:-->3 執行緒3--->5 執行緒1-->4 執行緒3--->6 執行緒2:-->4 執行緒3--->7 執行緒1-->5 執行緒3--->8 執行緒2:-->5 執行緒3--->9 執行緒1-->6 執行緒1-->7 執行緒1-->8 執行緒1-->9 執行緒2:-->6 執行緒2:-->7 main-->0 執行緒2:-->8 main-->1 執行緒2:-->9 main-->2 main-->3 main-->4 main-->5 main-->6 main-->7 main-->8 main-->9
主執行緒main先執行到s1.start()之前,此時雖然有建立的執行緒,但沒有啟動,所以參與到搶奪cpu的只有主執行緒一個,所以為單執行緒,當主執行緒main執行到s1.start(),啟動s1執行緒(此時搶奪cpu的執行緒有兩個為:s1執行緒和主執行緒main),此時cpu可能執行s1執行緒也可能執行主執行緒main,當主執行緒搶到cpu,主執行緒執行到s3.start(),此時有三個執行緒參與到搶奪cpu的行動中(s1執行緒,s3執行緒,主執行緒main),他們誰搶到cpu就執行誰的執行緒中的指令,當主執行緒搶到cpu,主執行緒main執行s2.start()時,此時有四個執行緒參與到搶奪cpu的行動中(s1執行緒,s3執行緒,主執行緒main,s2執行緒),誰搶到cpu就執行誰的指令,當主執行緒main搶到cpu後,執行到s1.join(),然後就告訴呼叫s1.join()的執行緒(這裡為主執行緒)你要阻塞,直到s1執行緒執行完後,主執行緒才可以執行(這裡可以理解為主執行緒才就可以參與到搶奪cpu資源中去了,此時實際有資格搶奪cpu的只有三個執行緒:s1執行緒,s2執行緒,s3執行緒,這三個執行緒誰搶到cpu就可以執行誰的指令,此時主執行緒main處於阻塞狀態,不參與搶奪cpu的行動),當s1執行緒執行完後,s2執行緒,s3執行緒和主執行緒三個中沒有執行完的(此時s2執行緒和s3執行緒可能執行完,也可能沒有執行完,主執行緒肯定沒有執行完 )有參與到搶奪cpu的行動中,誰搶到就執行誰的,直到主執行緒執行完(此時所有的執行緒也就執行完了)。我們也可以從了另一個例子驗證我們上面的解釋。我們只是修改了Student1和ReadMain的程式碼
public class Student1 extends Thread {
@Override
public void run(){
for(int i=1;i<10;i++){
System.out.println(getName()+"-->"+i);
if(i==5){
Student2 s2 = new Student2();
s2.setName("執行緒2");
s2.start();
try {
s2.join();
} catch (InterruptedException e) {
// TODO 自動生成的 catch 塊
e.printStackTrace();
}
}
}
}
}
public class ReadMain {
public static void main(String[] args) throws InterruptedException{
Student1 s1 = new Student1();
s1.setName("執行緒1"); //為執行緒命名
s1.start();
for(int i=0;i<10;i++){
System.out.println("main-->"+i);
}
}
}
main-->0
執行緒1-->1
main-->1
main-->2
main-->3
main-->4
main-->5
main-->6
執行緒1-->2
main-->7
執行緒1-->3
main-->8
執行緒1-->4
main-->9
執行緒1-->5
執行緒2:-->1
執行緒2:-->2
執行緒2:-->3
執行緒2:-->4
執行緒2:-->5
執行緒2:-->6
執行緒2:-->7
執行緒2:-->8
執行緒2:-->9
執行緒1-->6
執行緒1-->7
執行緒1-->8
執行緒1-->9
從上面的輸出可以解釋執行的順序:
前面的都一樣,當我們執行到s1.start()時,此時有兩個執行緒搶奪cpu(主執行緒 main和s1執行緒),當s1搶到cpu,執行其中的for迴圈,當執行到i==5時,進去if,建立了一個執行緒s2,並啟動了執行緒2,然後,有三個執行緒參與搶奪cpu(主執行緒main,s1執行緒,s2執行緒),若s1搶到cpu,則執行到s2.join(),此時呼叫 s2.join()的執行緒(s1執行緒)阻塞,此時有兩個執行緒(s2執行緒,主執行緒main)參與到搶奪cpu行動中(s1此時正在被阻塞,無法參與搶奪cpu,只有等到s2執行緒執行完後,s1執行緒才可以參與到搶奪cpu中),所以當s2執行緒執行完後,s1執行緒才可以和主執行緒main參與到搶奪cpu行動中(若沒有執行完則參與到其中)。
join()這裡不帶引數意思為一直等下去,無限等待,若加上引數則為呼叫執行緒等待的最大時間數,若在此時間內被呼叫的執行緒沒有執行完,則意味著呼叫執行緒可以重新參與到競爭cpu中去。