Java中有兩種實現多執行緒的方式。一是直接繼承Thread類,二是實現Runnable介面。那麼這兩種實現多執行緒的方式在應用上有什麼區別呢?

        為了回答這個問題,我們可以通過編寫一段程式碼來進行分析。我們用程式碼來模擬鐵路售票系統,實現通過四個售票點發售某日某次列車的100張車票,一個售票點用一個執行緒表示。

        我們首先這樣編寫這個程式:

Java程式碼
  1. class ThreadTest extends Thread{  
  2.   privateint ticket = 100;  
  3.   publicvoid run(){  
  4.     while(true){  
  5.       if(ticket > 0){  
  6.         System.out.println(Thread.currentThread().getName() +  
  7.           "is saling ticket" + ticket--);  
  8.       }else{  
  9.         break;  
  10.       }  
  11.     }  
  12.   }  
  13. }  

main測試類:
Java程式碼 收藏程式碼
  1. publicclass ThreadDome1{  
  2.   publicstaticvoid main(String[] args){  
  3.     ThreadTest t = new ThreadTest();  
  4.     t.start();  
  5.     t.start();  
  6.     t.start();  
  7.     t.start();  
  8.   }  
  9. }  

上面的程式碼中,我們用ThreadTest類模擬售票處的售票過程,run方法中的每一次迴圈都將總票數減1,模擬賣出一張車票,同時該車票號打印出來,直接剩餘的票數到零為止。在ThreadDemo1類的main方法中,我們建立了一個執行緒物件,並重復啟動四次,希望通過這種方式產生四個執行緒。從執行的結果來看我們發現其實只有一個執行緒在執行,這個結果告訴我們:一個執行緒物件只能啟動一個執行緒,無論你呼叫多少遍start()方法,結果只有一個執行緒。

      我們接著修改ThreadDemo1,在main方法中建立四個Thread物件:
Java程式碼 收藏程式碼
  1. publicclass ThreadDemo1{  
  2.   publicstaticvoid main(String[] args){  
  3.     new ThreadTest().start();  
  4.     new ThreadTest().start();  
  5.     new ThreadTest().start();  
  6.     new ThreadTest().start();  
  7.   }  
  8. }  

Java程式碼
  1. class ThreadTest extends Thread{  
  2.   privateint ticket = 100;  
  3.   publicvoid run(){  
  4.     while(true){  
  5.       if(ticket > 0){  
  6.         System.out.println(Thread.currentThread().getName() +   
  7.            " is saling ticket" + ticket--);  
  8.       }else{  
  9.         break;  
  10.       }  
  11.     }  
  12.   }  
  13. }  


     這下達到目的了嗎?

     從結果上看每個票號都被列印了四次,即四個執行緒各自賣各自的100張票,而不去賣共同的100張票。這種情況是怎麼造成的呢?我們需要的是,多個執行緒去處理同一個資源,一個資源只能對應一個物件,在上面的程式中,我們建立了四個ThreadTest物件,就等於建立了四個資源,每個資源都有100張票,每個執行緒都在獨自處理各自的資源。

     經過這些實驗和分析,可以總結出,要實現這個鐵路售票程式,我們只能建立一個資源物件,但要建立多個執行緒去處理同一個資源物件,並且每個執行緒上所執行的是相同的程式程式碼。在回顧一下使用介面編寫多執行緒的過程。
Java程式碼
  1. publicclass ThreadDemo1{  
  2.   publicstaticvoid main(String[] args){  
  3.     ThreadTest t = new ThreadTest();  
  4.     new Thread(t).start();  
  5.     new Thread(t).start();  
  6.     new Thread(t).start();  
  7.     new Thread(t).start();  
  8.   }  
  9. }  

Java程式碼
  1. class ThreadTest implements Runnable{  
  2.   privateint tickets = 100;  
  3.   publicvoid run(){  
  4.     while(true){  
  5.       if(tickets > 0){  
  6.         System.out.println(Thread.currentThread().getName() +  
  7.           " is saling ticket " + tickets--);  
  8.       }  
  9.     }  
  10.   }  
  11. }  


上面的程式中,建立了四個執行緒,每個執行緒呼叫的是同一個ThreadTest物件中的run()方法,訪問的是同一個物件中的變數(tickets)的例項,這個程式滿足了我們的需求。在Windows上可以啟動多個記事本程式一樣,也就是多個程序使用同一個記事本程式程式碼。

       可見,實現Runnable介面相對於繼承Thread類來說,有如下顯著的好處

(1)適合多個相同程式程式碼的執行緒去處理同一資源的情況,把虛擬CPU(執行緒)同程式的程式碼,資料有效的分離,較好地體現了面向物件的設計思想

(2)可以避免由於Java的單繼承特性帶來的侷限。我們經常碰到這樣一種情況,即當我們要將已經繼承了某一個類的子類放入多執行緒中,由於一個類不能同時有兩個父類,所以不能用繼承Thread類的方式,那麼,這個類就只能採用實現Runnable介面的方式了。

(3)有利於程式的健壯性,程式碼能夠被多個執行緒共享,程式碼與資料是獨立的。當多個執行緒的執行程式碼來自同一個類的例項時,即稱它們共享相同的程式碼。多個執行緒操作相同的資料,與它們的程式碼無關。當共享訪問相同的物件是,即它們共享相同的資料。當執行緒被構造時,需要的程式碼和資料通過一個物件作為建構函式實參傳遞進去,這個物件就是一個實現了Runnable介面的類的例項。