「轉」http://www.360doc.com/content/10/1219/22/573136_79607619.shtmlhtml
何時讓線程實現Runnable接口,何時讓線程繼承Thread類?java
JDK幫助文檔中的原話:Runnable 接口應該由那些打算經過某一線程執行其實例的類來實現
(不明白是啥意思)
孫鑫老師的原話:當不須要改變一個線程中除了run()方法之外的其餘方法時,讓線程實現Runnable接口。
(明白是什麼意思,但不知道有什麼用 汗!!!)安全
若是讓一個線程實現Runnable接口,那麼當調用這個線程的對象開闢多個線程時,可讓這些線程調用同一個變量;若這個線程是由繼承Thread類而來,則要經過內部類來實現上述功能,利用的就是內部類可任意訪問外部變量這一特性。
例子程序:多線程
1 public class ThreadTest 2 { 3 public static void main(String[] args) 4 { 5 MyThread mt=new MyThread(); 6 new Thread(mt).start(); //經過實現Runnable的類的對象來開闢第一個線程
7 new Thread(mt).start(); //經過實現Runnable的類的對象來開闢第二個線程
8 new Thread(mt).start(); //經過實現Runnable的類的對象來開闢第三個線程 9 //因爲這三個線程是經過同一個對象mt開闢的,因此run()裏方法訪問的是同一個index
10 } 11 } 12
13 class MyThread implements Runnable //實現Runnable接口
14 { 15 int index=0; 16 public void run() 17 { 18 for(;index<=200;) 19 System.out.println(Thread.currentThread().getName()+":"+index++); 20 } 21 }
1 public class ThreadTest 2 { 3 public static void main(String[] args) 4 { 5 MyThread mt=new MyThread(); 6 mt.getThread().start(); //經過返回內部類的對象來開闢第一個線程
7 mt.getThread().start(); //經過返回內部類的對象來開闢第二個線程
8 mt.getThread().start(); //經過返回內部類的對象來開闢第三個線程 9 //因爲這三個線程是經過同一個匿名對象來開闢的,因此run()裏方法訪問的是同一個index
10 } 11 } 12
13 class MyThread 14 { 15 int index=0; 16 private class InnerClass extends Thread //定義一個內部類,繼承Thread
17 { 18 public void run() 19 { 20 for(;index<=200;) 21 System.out.println(getName()+":"+index++); 22 } 23 } 24 Thread getThread() //這個函數的做用是返回InnerClass的一個匿名對象
25 { 26 return new InnerClass(); 27 } 28 } 29 //這裏有一個問題:若是內部類要訪問一個外部變量或方法,那麼這個變量或方法必須定義爲final,但爲何這裏的變量index不用定義爲final就能夠被內部類訪問?
一、 認識Thread和Runnable函數
Java中實現多線程有兩種途徑:繼承Thread類或者實現Runnable接口。Runnable是接口,建議用接口的方式生成線程,由於接口能夠實現多繼承,何況Runnable只有一個run方法,很適合繼承。在使用Thread的時候只需繼承Thread,而且new一個實例出來,調用 start()方法便可以啓動一個線程。spa
Thread Test = new Thread();操作系統
Test.start();線程
在使用Runnable的時候須要先new一個實現Runnable的實例,以後啓動Thread便可。code
Test impelements Runnable;htm
Test t = new Test();
Thread test = new Thread(t);
test.start();
總結:Thread和Runnable是實現java多線程的2種方式,runable是接口,thread是類,建議使用runable實現 java多線程,無論如何,最終都須要經過thread.start()來使線程處於可運行狀態。
二、 認識Thread的start和run
1) start:
用start方法來啓動線程,真正實現了多線程運行,這時無需等待run方法體代碼執行完畢而直接繼續執行下面的代碼。經過調用Thread類的 start()方法來啓動一個線程,這時此線程處於就緒(可運行)狀態,並無運行,一旦獲得cpu時間片,就開始執行run()方法,這裏方法 run()稱爲線程體,它包含了要執行的這個線程的內容,Run方法運行結束,此線程隨即終止。
2) run:
run()方法只是類的一個普通方法而已,若是直接調用Run方法,程序中依然只有主線程這一個線程,其程序執行路徑仍是隻有一條,仍是要順序執行,仍是要等待run方法體執行完畢後纔可繼續執行下面的代碼,這樣就沒有達到寫線程的目的。
總結:調用start方法方可啓動線程,而run方法只是thread的一個普通方法調用,仍是在主線程裏執行。
三、 線程狀態說明
線程狀態從大的方面來講,可歸結爲:初始狀態、可運行狀態、不可運行狀態和消亡狀態,具體可細分爲上圖所示7個狀態,說明以下:
1) 線程的實現有兩種方式,一是繼承Thread類,二是實現Runnable接口,但無論怎樣,當咱們new了thread實例後,線程就進入了初始狀態;
2) 當該對象調用了start()方法,就進入可運行狀態;
3) 進入可運行狀態後,當該對象被操做系統選中,得到CPU時間片就會進入運行狀態;
4) 進入運行狀態後case就比較多,大體有以下情形:
﹒run()方法或main()方法結束後,線程就進入終止狀態;
﹒當線程調用了自身的sleep()方法或其餘線程的join()方法,就會進入阻塞狀態(該狀態既中止當前線程,但並不釋放所佔有的資源)。當 sleep()結束或join()結束後,該線程進入可運行狀態,繼續等待OS分配時間片;
﹒當線程剛進入可運行狀態(注意,還沒運行),發現將要調用的資源被鎖牢(synchroniza,lock),將會當即進入鎖池狀態,等待獲取鎖標記(這時的鎖池裏也許已經有了其餘線程在等待獲取鎖標記,這時它們處於隊列狀態,既先到先得),一旦線程得到鎖標記後,就轉入可運行狀態,等待OS分配 CPU時間片;
﹒當線程調用wait()方法後會進入等待隊列(進入這個狀態會釋放所佔有的全部資源,與阻塞狀態不一樣),進入這個狀態後,是不能自動喚醒的,必須依靠其餘線程調用notify()或notifyAll()方法才能被喚醒(因爲notify()只是喚醒一個線程,但咱們由不能肯定具體喚醒的是哪個線程,也許咱們須要喚醒的線程不可以被喚醒,所以在實際使用時,通常都用notifyAll()方法,喚醒有所線程),線程被喚醒後會進入鎖池,等待獲取鎖標記。
﹒當線程調用stop方法,便可使線程進入消亡狀態,可是因爲stop方法是不安全的,不鼓勵使用,你們能夠經過run方法裏的條件變通實現線程的 stop。