1. 程式人生 > >Java多執行緒-基礎篇(一)

Java多執行緒-基礎篇(一)

多執行緒---基礎篇,本文主要針對多執行緒的基礎進行復習,內容包括執行緒的理解,建立方式,Thread類函式理解;
1、執行緒的理解:OS系統角度:每個執行的程式都會被作業系統建立對應的程序(包括分配的資源、PCB等),程序是作業系統分配資源的基本單位(理解:程式執行需要空間,作業系統建立對應程序時就為之分配了相應的空間),切換程序時需要作中斷處理、保護現場等,使得系統的併發度受到一定影響;為了提高併發度,提出了執行緒的概念,執行緒可理解為一個更小的程序,一個程序可以建立多個執行緒,它們共享程序的資源,同時擁有自己的一些資源(如堆疊空間,很小),那麼OS線上程中切換就不像切換程序那麼耗費資源了,從而併發度就提高了。
總之:執行緒時程序的一部分,在執行JAVA程式時,OS為之建立一個程序,該程序又可建立多個執行緒,即所謂的單程序多執行緒。
2、執行緒的兩種建立方式
執行緒是要執行程式碼的,即要完成任務的,所以建立執行緒之前必須明白執行緒要做什麼,即任務是什麼?=>任務當然就是run()方法裡面的內容了
(1)繼承Thread類,覆蓋其run()方法,如下程式碼:以內部類的方式建立執行緒

		//執行緒的第一種建立方式,繼承Thread類,覆蓋run()方法
		new Thread(){
			private int i=0;
			public void run(){
				for(int i=0;i<100;i++){
					System.out.println("Thread....i="+i);
				}
			}
		}.start();
注意:start()方法為Thread類中的方法,該方法有兩個作用,一是開啟執行緒,二是呼叫run()方法
(2)實現Runnable介面

		//執行緒的第二種建立方式,實現Runnable介面,覆蓋run()方法
		new Thread(new Runnable(){
			public void run(){
				for(int i=0;i<100;i++){
					System.out.println("Runnable....i="+i);
				}
			}
		}).start();

兩種方式對比:如果檢視許多優秀的多執行緒程式碼,你可以發現,大多數採用了後者方式建立程序,WHY?我們應該從OOP的角度思考問題,任務是什麼?任務中有自己的執行方式,有自己的屬性,所以我們應該將任務封裝成為一個類,第二種方式將執行緒與任務分開,將OOP的思想運用到了。
考題:以下方式建立執行緒會執行哪個run()方法?

		new Thread(new Runnable(){
			public void run(){
				for(int i=0;i<10;i++)
					System.out.println("2....");
			}
		}){
			public void run(){
				for(int i=0;i<10;i++)
					System.out.println("1....");
			}
		}.start();
答案:輸出1....,即執行下面哪個run()方法。
解析:此題設計內部類的一些知識,這樣建立執行緒意思:建立了一個內部類,即Thread的子類,並實現了run()方法(列印1....),在建立該物件時,呼叫的不是預設的建構函式,而是呼叫的帶引數的建構函式,傳遞了一個Runnable例項物件,也實現了run()方法(列印2...);此時該呼叫哪個?實際上回到面向物件的思想上,參閱JDK文件,Thread類時實現了Runnable介面的,故Thread類實現了run()方法,它內部實際存在一個Runnable例項task,若Thread類的例項呼叫run()方法,實際上進行了判斷

	if(task!=null){
		task.run();//其中task時Runnable的一個例項
	}
task就是我們封裝的任務類的例項,所以通過Runnable建立執行緒的原理大家應該明白了,那現在Thread的子類又實現了run()方法,子類的方法會覆蓋父類的run()方法,所以start()開啟的是子類的run()方法。

3、Thread類的方法
Thread類包含了許多控制執行緒的方法,如靜態方法Thread.currentThread()得到當前正在執行的執行緒,成員方法:start()、isAlive()、setPriority(p:int)、join()、sleep(mills:long)、yield()等。
其中setProority(p:int)設定優先順序,並不代表優先順序高的執行緒一定會先執行,應該理解為執行緒獲得CPU的概率更高;join()方法:使得當前執行緒放棄CPU,呼叫者獲得CPU執行,呼叫者執行完後才恢復之前的執行緒執行;sleep()為暫停當前的執行執行緒。
		Thread t1=new Thread(new Runnable(){
			public void run(){
				for(int i=0;i<100;i++)
					System.out.println(Thread.currentThread().getName()+"...2....");
			}
		});
		Thread t2=new Thread(){
			public void run(){
				for(int i=0;i<100;i++){
					System.out.println(Thread.currentThread().getName()+"...1....");
				}
			}
		};
		Thread t3=new Thread(){
			public void run(){
				for(int i=0;i<100;i++)
					System.out.println(Thread.currentThread().getName()+"...3....");
			}
		};
		t1.setPriority(Thread.MAX_PRIORITY);
		t2.setPriority(Thread.NORM_PRIORITY);
		t3.setPriority(Thread.MIN_PRIORITY);
		t1.start();
		t2.start();
		t3.start();
輸出結果為:

Thread-1...1....
Thread-2...3....
Thread-0...2....
Thread-2...3....
Thread-1...1....
Thread-2...3....
可以看到,優先順序高的執行緒不總是能搶到CPU資源。