線程的啟動的兩種方法,Runnable接口,run()的調用
實現並啟動線程有兩種方法
1、寫一個類繼承自Thread類,重寫run方法。用start方法啟動線程
2、寫一個類實現Runnable接口,實現run方法。用new Thread(Runnable target).start()方法來啟動
多線程原理:相當於玩遊戲機,只有一個遊戲機(cpu),可是有很多人要玩,於是,start是排隊!等CPU選中你就是輪到你,你就run(),當CPU的運行的時間片執行完,這個線程就繼續排隊,等待下一次的run()。
調用start()後,線程會被放到等待隊列,等待CPU調度,並不一定要馬上開始執行,只是將這個線程置於可動行狀態。然後通過JVM,線程Thread會調用run()方法,執行本線程的線程體。先調用start後調用run,這麽麻煩,為了不直接調用run?
1.start()方法來啟動線程,真正實現了多線程運行。這時無需等待run方法體代碼執行完畢,可以直接繼續執行下面的代碼;通過調用Thread類的start()方法來啟動一個線程, 這時此線程是處於就緒狀態, 並沒有運行。 然後通過此Thread類調用方法run()來完成其運行操作的, 這裏方法run()稱為線程體,它包含了要執行的這個線程的內容, Run方法運行結束, 此線程終止。然後CPU再調度其它線程。
2.run()方法當作普通方法的方式調用。程序還是要順序執行,要等待run方法體執行完畢後,才可繼續執行下面的代碼; 程序中只有主線程——這一個線程, 其程序執行路徑還是只有一條, 這樣就沒有達到寫線程的目的。
記住:多線程就是分時利用CPU,宏觀上讓所有線程一起執行 ,也叫並發
1 public class Test { 2 public static void main(String[] args) { 3 Runner1 runner1 = new Runner1(); 4 Runner2 runner2 = new Runner2(); 5 // Thread(Runnable target) 分配新的 Thread 對象。 6 Thread thread1 = new Thread(runner1);7 Thread thread2 = new Thread(runner2); 8 // thread1.start(); 9 // thread2.start(); 10 thread1.run(); 11 thread2.run(); 12 } 13 } 14 15 class Runner1 implements Runnable { // 實現了Runnable接口,jdk就知道這個類是一個線程 16 public void run() { 17 for (int i = 0; i < 100; i++) { 18 System.out.println("進入Runner1運行狀態——————————" + i); 19 } 20 } 21 } 22 23 class Runner2 implements Runnable { // 實現了Runnable接口,jdk就知道這個類是一個線程 24 public void run() { 25 for (int i = 0; i < 100; i++) { 26 System.out.println("進入Runner2運行狀態==========" + i); 27 } 28 } 29 }
以上整理來自:http://blog.csdn.net/xuxurui007/article/details/7685076
【線程的創建和啟動的步驟(實現Runnable接口方式)】
1.定義Runnable接口的實現類,並重寫其中的run方法。run()方法的方法體是線程執行體。
class SonThread implement Runnable{
public void run(){
......
}
}
2.創建Runnable接口實現類的實例。 sonThread s1=new SonThread();
3.用該實例作為Thread的target來創建Thread對象。 Thread t1 =new Thread(s1);
4.調用該對象的start()方法啟動線程。 t1.start();
【註意一:關於命名】
在創建Thread 對象的時候可以為該Thread對象指定一個名字
【註意二:Thread的構造方法】
Runnable對象作為Thread對象的target,Runnable實現類裏面包含run方法僅僅作為執行體。也就是說Thread類的作用是把run方法包裝成線程的執行體。
實際運行的線程對象依然是Thread實例,只是該Thread線程負責執行其target的run方法。
1 //1.1定義Runnable接口的實現類 2 class SecondThread implements Runnable{ 3 4 //1.2重寫其中的run方法 5 @Override 6 public void run() { 7 for(int i=0;i<10;i++){ 8 System.out.println(Thread.currentThread().getName()+"===="+i); 9 } 10 } 11 12 } 13 public class Demo2 { 14 15 public static void main(String[] args) { 16 //2.創建Runnable的接口實現類的實例 17 SecondThread s1=new SecondThread(); 18 SecondThread s2=new SecondThread(); 19 //2.用Runnable的接口實現類的實例作為Thread的target,創建Thread對象 20 Thread t1=new Thread(s1); 21 Thread t2=new Thread(s2,"Higgin"); //創建Thread對象的同時可以為之命名 22 23 //啟動線程 24 t1.start(); 25 t2.start(); 26 27 for(int i=0;i<10;i++){ 28 System.out.println(Thread.currentThread().getName()+"===="+i); 29 } 30 } 31 }
以上整理來自:http://www.cnblogs.com/HigginCui/p/5901593.html
通過JDK源碼解析Thread(Runable target ...)調用的是哪個run方法
代碼1:
1 new Thread(new Runnable() { 2 @Override 3 public void run() { 4 System.out.println("Run of Runnable"); 5 } 6 }) { 7 public void run() { 8 System.out.println("Run of Thread"); 9 } 10 }.start();
代碼2:
1 new Thread(new Runnable() { 2 @Override 3 public void run() { 4 System.out.println("Run of Runnable"); 5 } 6 }) { 7 public void run() { 8 System.out.println("Run of Thread"); 9 super.run(); 10 } 11 }.start();
首先,我們來看一下JDK的Thread源碼,片段 3 如下:
1 private Runnable target;
public void run() { if (target != null) { target.run(); } }
在run()方法中,首先會檢查target是否為空,如果不是,則執行該target的run()方法。
那麽,對於上面兩段代碼的執行,也就清楚了。
在第一個代碼段 1 中,重寫了Thread的run()方法,同時傳入了一個Runnable對象,該對象也實現了run()方法。該Thread對象調用start()方法後,會執行該對象重寫的run()方法,其輸出結果也就是Run of Thread,輸出完後,run()方法返回,該線程對象的生命周期也就結束了。
在第二個代碼段 2 中,同樣也重寫了Thread的run()方法,同時傳入了一個Runnable對象,實現了run()方法。唯一不同的是,在Thread重寫的run方法中,在打印輸出後,還執行了super.run(),這就有意思了。
首先,該線程啟動運行後,執行其重寫的run()方法,輸出Run of Thread。
接下來調用super.run(),也就是調用超類的run()方法,而該超類的run()方法,也就是JDK定義的Thread類的run(),其執行如上代碼段 3 所示;顯然target不為空,這時候會調用該對象的run()方法,會輸出Run of Runnable.。
如果,上面的Thread並未重寫run()方法,那麽,執行的結果還是一樣。首先會執行該Thread的run()方法,因為此時並未重寫該方法,所以還是會調用JDK定以的run()方法,也就是上面的代碼段 3,在該代碼段中會判斷target是否為空,顯然不是,所以會調用Runnable對象實現的run()方法。
總結:對於Thread(Runnable target ...),不管傳入的Target是否為空,首先都會執行Thread自己的run()方法。如果重寫了該方法且該方法中沒有super.run(),那麽是永遠不會調用Runnable實現的run()方法;如果沒有重寫該方法,則會去判斷target是否為空,以此來決定調用target實現的run()方法;如果重寫了該方法,且該方法中有super.run(),在執行完該語句之前的所有代碼後,會判斷target是否為空,以此來決定調用target實現的run()方法,執行完後,接著執行該語句之後的代碼。
以上整理來自:http://blog.csdn.net/guguituzi/article/details/44593863
線程的啟動的兩種方法,Runnable接口,run()的調用