1. 程式人生 > >JAVA面試題 啟動執行緒是start()還是run()?為什麼?

JAVA面試題 啟動執行緒是start()還是run()?為什麼?

面試官:請問啟動執行緒是start()還是run()方法,能談談嗎?

應聘者:start()方法

當用start()開始一個執行緒後,執行緒就進入就緒狀態,使執行緒所代表的虛擬處理機處於可執行狀態,這意味著它可以由JVM排程並執行。但是這並不意味著執行緒就會立即執行。只有當cpu分配時間片時,這個執行緒獲得時間片時,才開始執行run()方法。start()是方法,它呼叫run()方法.而run()方法是你必須重寫的. run()方法中包含的是執行緒的主體(真正的邏輯)。  

 

繼承Thread類的啟動方式

public class ThreadTest { 
   public static void main(String[] args) {
        MyThread t =new MyThread();
        t.start();
    } 
}

class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println("Hello World!");
    }
}

 

實現Runnable介面的啟動方式

public class ThreadTest { 
      public static void main(String[] args) {
        Thread t =new Thread(new MyRunnable());
        t.start();
    }
}

class MyRunnable implements Runnable{
    @Override
    public void run() {
        System.out.println("Hello World!");
    }
}

實際上這兩種啟動執行緒的方式原理是一樣的。首先都是呼叫本地方法啟動一個執行緒,其次是在這個執行緒裡執行目標物件的run()方法。那麼這個目標物件是什麼呢?為了弄明白這個問題,我們來看看Thread類的run()方法的實現:

public void run() { 
    if (target != null) { 
       target.run(); 
    } 
} 

當我們採用實現Runnable介面的方式來實現執行緒的情況下,在呼叫new Thread(Runnable target)構造器時,將實現Runnable介面的類的例項設定成了執行緒要執行的主體所屬的目標物件target,當執行緒啟動時,這個例項的 run()方法就被執行了。

當我們採用繼承Thread的方式實現執行緒時,執行緒的這個run()方法被重寫了,所以當執行緒啟動時,執行的是這個物件自身的 run()方法。

 

總結起來:如果我們採用的是繼承Thread類的方式,那麼這個target就是執行緒物件自身,如果我們採用的是實現Runnable介面的方式,那麼這個target就是實現了Runnable介面的類的例項。

 

我們再來看一道混跡於各大面試公司筆試的題目:

 public class EqualsTest {
     public static void main(String args[]) {
         Thread t = new Thread() {
             public void run() {
                 pong();
             }
         };
         t.run();
         System.out.print("ping");

    }

    static void pong() {
        System.out.print("pong");
    }
}

這裡的標準答案是:pongping

這裡直接呼叫執行緒的run方法,就相當於呼叫普通方法一樣,由上往下執行,所以最後的結果是pongping。但是如果上面改成t.start()之後,這個結果就不固定了,因為這裡有兩個執行緒(其實還有一個守護執行緒,這裡就先忽略),main執行緒和 t 執行緒,這兩個執行緒獲得cpu的時間就會不固定了,誰先獲得CPU執行權,誰就先列印結果,所以最後的結果可能pongping也可能是pingpong。

&n