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