1. 程式人生 > >建立多執行緒的兩種方式

建立多執行緒的兩種方式

API中告訴我們建立執行緒有2種方式:
第一種:
1、定義一個類繼承Thread
2、子類複寫Thread類中的run方法
3、建立子類物件(子類就是一個執行緒類)

4、啟動子類物件

/*
 * 演示建立執行緒的第一種方式
 */
//定義子類,繼承Thread
class Demo extends Thread{
	
	//複寫run方法
	public void run(){
		
		for( int i=0;i<20;i++ ){
			System.out.println("demo run i = "+i);
		}
	}
}

public class ThreadDemo {
	public static void main(String[] args) {
		
		//建立子類物件
		Demo d = new Demo();
		//啟動執行緒
		d.start();

		for( int i=0;i<20;i++ ){
			System.out.println("main i = "+i);
		}
		
	}
}
分析:
1)、為什麼要繼承Thread類?
執行緒是計算機中程式執行的一個獨立單元,這個單元Java使用Thread類進行了描述。現在我們需要自己使用執行緒,執行我們自己的某些程式碼。
Thread類是Java中提供的原生的類,而我們具體需要操作執行緒時,不能直接去使用Thread,如果直接去使用的Thread,導致原生的Thread類無法知道我們後期真正需要讓執行緒執行的程式碼。
API中告訴我們需要自己定義一個類繼承Thread,我們自己的類繼承了Thread那麼自己的類就變成執行緒類,就繼承到Thread類中的所有功能,我們自己的類就可以去使用Thread類中定義的所有操作執行緒的功能。

繼承Thread類的目的就是讓自己的類變成執行緒類。可以去操作執行緒。

2)、執行緒是計算機中程式執行的一個獨立單元,這個單元Java使用Thread類進行了描述。現在我們需要自己使用執行緒,執行我們自己的某些程式碼。
Thread類是Java中提供的原生的類,而我們具體需要操作執行緒時,不能直接去使用Thread,如果直接去使用的Thread,導致原生的Thread類無法知道我們後期真正需要讓執行緒執行的程式碼。
API中告訴我們需要自己定義一個類繼承Thread,我們自己的類繼承了Thread那麼自己的類就變成執行緒類,就繼承到Thread類中的所有功能,我們自己的類就可以去使用Thread類中定義的所有操作執行緒的功能。

繼承Thread類的目的就是讓自己的類變成執行緒類。可以去操作執行緒。

2)、為什麼要複寫run方法
我們開啟執行緒的目的是讓多部分程式碼同時執行,讓執行緒去執行我們自己的某些程式碼,而這些程式碼需要交給執行緒執行,那麼我們就必須按照執行緒執行時會呼叫的某些固定的功能。
當我們呼叫start方法的時候,JVM在底層會自動的呼叫run方法,而run方法中的程式碼就會被某個執行緒去執行。
而我們開啟執行緒的目的就是希望執行緒執行某些程式碼,也就是隻要大家把需要執行緒執行的程式碼書寫在run方法中,一旦開啟執行緒,run方法會自動的執行  過,那麼就會 導致 書寫在run方法中的所有程式碼會被當前某個執行緒去呼叫執行。
複寫run方法的目的:就是希望在run方法中書寫執行緒要執行的那麼程式碼。
執行緒要執行的程式碼:稱為執行緒的任務。
3)為什麼不直接呼叫run方法,而呼叫start方法
如果我們直接呼叫run方法,這時雖然有執行緒物件,但是並沒有讓執行緒真正開啟,而不開啟執行緒,直接通過執行緒物件呼叫run方法,這個和我們以前學習的物件呼叫普通方法沒有任何區別,這些呼叫的功能都會在主執行緒所在的區域中執行。

如果我們有了執行緒物件,希望執行緒可以獨立去執行,只能手動呼叫Thread類提供的start方法,才能在棧記憶體中開啟一個新的執行通道(路徑),這樣才能保證run方法會被載入到新的執行路徑中去執行。

開啟執行緒的第二種方式

1、定義一個類 實現 Runnable 介面
2、實現介面中的run方法
3、建立實現類的物件
4、建立Thread物件,把實現類物件作為引數傳遞
5、Thread物件開啟執行緒

/*
 * 演示建立執行緒的第二種方式
 */
class Demo2 implements Runnable{
	
	//實現run方法
	public void run() {
		for( int i=0;i<20;i++ ){
			System.out.println("demo2 run i = "+i);
		}
	}
}
public class ThreadDemo2 {
	public static void main(String[] args) {
		
		//建立實現類的物件
		Demo2 d  = new Demo2();
		
		//建立Thread物件
		Thread t = new  Thread( d );
		
		//開啟執行緒
		t.start();
		
		for( int i=0;i<20;i++ ){
			System.out.println("main i = "+i);
		}
	}
}<span style="color:#ff0000;">
</span>
分析:實現Runnable的原理:
1)、Java中繼承的侷限性
Java只支援單繼承,不支援多繼承。如果一個類已經有父類了,但這個類中有部分程式碼需要多執行緒操作,這時我們就沒有辦法再讓這個類去繼承Thread。也就是Java中提供的第一種方式就無法使用。導致沒有辦法去操作多執行緒了。

Thread類是描述執行緒,Thread類就應該只定義如何去操作執行緒的功能,在Thread中提供了一個run方法,而這個run方法是專門用來明確執行緒要執行的任務的方法。於是就run方法從Thread類中抽離出來,專門定義了一個介面,後期真正在開發中,如果要明確執行緒的任務,找對應的介面,如果要操作執行緒就直接找Thread。
2)、Java中提供的介面的作用
           1、 給事物體現新增(增加)擴充套件功能。
           2、給事物雙方定義規則。
Runnable介面它其實是在定義執行緒中操作任務的一個規則。執行緒是可以操作任務的,而任務是需要後來程式書寫和明確的。只有我們明確的任務符合Runnable介面的規範,那麼Thread才能去真正呼叫run方法。
3)、其他的技術問題:
1、我們在建立Thread類的時候,其實只是明確了執行緒物件
2、書寫的實現了Runnable介面的類,相當於明確了執行緒要執行的任務類,當我們建立了實現類物件,就相當於明確了執行緒要執行的任務物件。
3、需要在建立Thread物件的時候,把執行緒的任務物件傳遞給Thread,這樣就讓執行緒物件和任務物件之間產生了關係。
4、我們呼叫Thread的start方法的時候,就會根據對應的關係調用到其中的run方法。