1. 程式人生 > >Thread的join()方法理解

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);
		}
	}
}
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);
		}
	}
}
我們在沒有join()方法之前,執行結果:
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-->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
可以看出執行緒1先執行完後,再是主執行緒main執行,join()方法的官方解釋是:等待該執行緒終止。根據上面的結果 我們可以推測是讓呼叫s1.join()的執行緒(這裡既是主執行緒main)等待被呼叫執行緒(這裡既是執行緒1)執行完後再執行呼叫s1.join()的 執行緒(main執行緒),即將呼叫執行緒(main執行緒)阻塞。

這裡只有兩個執行緒,我們現在在新增兩個執行緒執行緒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中去。