面試官:請問啓動線程是start()仍是run()方法,能談談嗎?java
應聘者:start()方法面試
當用start()開始一個線程後,線程就進入就緒狀態,使線程所表明的虛擬處理機處於可運行狀態,這意味着它能夠由JVM調度並執行。可是這並不意味着線程就會當即運行。只有當cpu分配時間片時,這個線程得到時間片時,纔開始執行run()方法。start()是方法,它調用run()方法.而run()方法是你必須重寫的. run()方法中包含的是線程的主體(真正的邏輯)。 ide
繼承Thread類的啓動方式spa
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()方法就被執行了。blog
當咱們採用繼承Thread的方式實現線程時,線程的這個run()方法被重寫了,因此當線程啓動時,執行的是這個對象自身的 run()方法。繼承
總結起來:若是咱們採用的是繼承Thread類的方式,那麼這個target就是線程對象自身,若是咱們採用的是實現Runnable接口的方式,那麼這個target就是實現了Runnable接口的類的實例。接口
咱們再來看一道混跡於各大面試公司筆試的題目:get
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。