【通過繼承Thread】
一個Thread對象只能創建一個線程,即使它調用多次的.start()也會只運行一個的線程。
【看下面的代碼 & 輸出結果】
1 package Test; 2 3 class CTest extends Thread { 4 private int tickte = 20; 5 6 public void run() { 7 while (true) { 8 if (tickte > 0) { 9 System.out.println(Thread.currentThread().getName() + " 出售票 " 10 + tickte--); 11 } else { 12 System.exit(0); 13 } 14 } 15 } 16 17 } 18 19 public class Demo3 { 20 public static void main(String[] args) { 21 // new CTest().start(); 22 // new CTest().start(); 23 Thread t1 = new CTest();//創建一個線程 24 t1.start(); 25 t1.start(); 26 } 27 } 28 29 // 30 Thread-0 出售票 20 31 Thread-0 出售票 19 32 Thread-0 出售票 18 33 Thread-0 出售票 17 34 Thread-0 出售票 16 35 Thread-0 出售票 15 36 Thread-0 出售票 14 37 Thread-0 出售票 13 38 Thread-0 出售票 12 39 Thread-0 出售票 11 40 Thread-0 出售票 10 41 Thread-0 出售票 9 42 Thread-0 出售票 8 43 Thread-0 出售票 7 44 Thread-0 出售票 6 45 Thread-0 出售票 5 46 Thread-0 出售票 4 47 Thread-0 出售票 3 48 Thread-0 出售票 2 49 Thread-0 出售票 1
通過調用當前線程對象的名字Thread.currentThread.getName(),根據結果可以看出,只運行了一個線程。
這就說明了一個問題,每創建一個Thread對象,只能創建一個線程。
下面是創建多個Thread對象。
package Test; class CTest extends Thread { private int tickte = 20; public void run() { while (true) { if (tickte > 0) { System.out.println(Thread.currentThread().getName() + " 出售票 " + tickte--); } else { System.exit(0); } } } } public class Demo3 { public static void main(String[] args) { new CTest().start(); new CTest().start(); } }
上面啟動了兩個線程對象,他們各自執行自己的互不影響。
結果:
Thread-0 出售票 20 Thread-1 出售票 20 Thread-1 出售票 19 Thread-0 出售票 19 Thread-0 出售票 18 Thread-0 出售票 17 Thread-0 出售票 16 Thread-0 出售票 15 Thread-0 出售票 14 Thread-0 出售票 13 Thread-0 出售票 12 Thread-0 出售票 11 Thread-0 出售票 10 Thread-0 出售票 9 Thread-0 出售票 8 Thread-0 出售票 7 Thread-0 出售票 6 Thread-0 出售票 5 Thread-0 出售票 4 Thread-0 出售票 3 Thread-0 出售票 2 Thread-0 出售票 1 Thread-1 出售票 18 Thread-1 出售票 17 Thread-1 出售票 16 Thread-1 出售票 15 Thread-1 出售票 14 Thread-1 出售票 13 Thread-1 出售票 12 Thread-1 出售票 11 Thread-1 出售票 10 Thread-1 出售票 9 Thread-1 出售票 8 Thread-1 出售票 7 Thread-1 出售票 6 Thread-1 出售票 5 Thread-1 出售票 4 Thread-1 出售票 3 Thread-1 出售票 2 Thread-1 出售票 1
可以看出是創建了兩個線程。他們各自執行自己的線程,互不影響。
【多個線程操作一個對象】
01 public class ThreadDemo9_4 02 { 03 public static void main(String [] args) 04 { 05 TestThread t = new TestThread() ; 06 // 啟動了四個線程,並實現了資源共享的目的 07 new Thread(t).start(); 08 new Thread(t).start(); 09 new Thread(t).start(); 10 new Thread(t).start(); 11 } 12 } 13 class TestThread implements Runnable 14 { 15 private int tickets=20; 16 public void run() 17 { 18 while(true) 19 { 20 if(tickets>0) 21 System.out.println(Thread.currentThread().getName()+"出售票"+tickets--); 22 } 23 } 24 }
上面通過實現Runnable的方式啟動四個進程,但是他們共同操縱同一對象,實現了資源的互斥共享。
結果:
Thread-1 出售票 10 Thread-1 出售票 8 Thread-1 出售票 7 Thread-1 出售票 6 Thread-1 出售票 5 Thread-2 出售票 9 Thread-1 出售票 4 Thread-1 出售票 2 Thread-1 出售票 1 Thread-2 出售票 3
可以看出,雖然是兩個線程,但是操作的卻只有一個資源。但是從程序的輸出結果來看,盡管啟動了兩個線程對象,但是結果都是操縱了同一個資源,實現了資源共享的目的。
可見,實現Runnable接口相對於繼承Thread類來說,有如下顯著的優勢:
(1)、 適合多個相同程序代碼的線程去處理同一資源的情況,把虛擬CPU(線程)同程序的代碼、數據有效分離,較好地體現了面向對象的設計思想。
(2)、 可以避免由於Java的單繼承特性帶來的局限。開發中經常碰到這樣一種情況,即:當要將已經繼承了某一個類的子類放入多線程中,由於一個類不能同時有兩個父類,所以不能用繼承Thread類的方式,那么就只能采用實現Runnable接口的方式了。
(3)、 增強了程序的健壯性,代碼能夠被多個線程共享,代碼與數據是獨立的。當多個線程的執行代碼來自同一個類的實例時,即稱它們共享相同的代碼。多個線程可以操作相同的數據,與它們的代碼無關。當共享訪問相同的對象時,即共享相同的數據。當線程被構造時,需要的代碼和數據通過一個對象作為構造函數實參傳遞進去,這個對象就是一個實現了Runnable接口的類的實例。
可以將一個Runnable接口的實例化對象作為參數去實例化Thread類對象。在實際的開發中,希望讀者盡可能去使用Runnable接口去實現多線程機制。